17

Question

How does one programatically (without touching the AndroidManifext.xml) set the theme of an Activity so that it looks like a dialog?

Note: I am ok with modifying the AndroidManifext.xml as long as it does not need to be modified in order to switch between making it look like a normal activity or a dialog.

What I've tried so far

I tried the following as per this stackoverflow answer:

public class DialogActivity extends Activity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        setTheme(android.R.style.Theme_DeviceDefault_Dialog);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
        Log.d(TAG,"Build.VERSION.SDK_INT: "+Build.VERSION.SDK_INT); // 23
    }
}

But it ends up blacking out everything in the background.

I also saw this stackoverflow answer, and tried:

public class DialogActivity extends Activity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        setTheme(android.R.style.Theme_DeviceDefault_Dialog);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
        getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
    }
}

but it ends up making everything black.

What do? Thank you.

Community
  • 1
  • 1
Eric
  • 16,397
  • 8
  • 68
  • 76
  • Possibly duplicate: http://stackoverflow.com/questions/1979369/android-activity-as-a-dialog. May be you can also interested in this: https://github.com/pingpongboss/StandOut – T D Nguyen Mar 07 '16 at 00:48
  • @NguyenDoanTung thank you. I saw that post too, but most of those answers involve modifying the `AndroidManifest.xml` which I don't want to do. I tried the first method mentioned in http://stackoverflow.com/a/22216966/2898715, but it didn't produce satisfactory results as mentioned in my question. Also, thank you for the github link, I checked it out, however I really hope there is a simpler solution. – Eric Mar 07 '16 at 00:58
  • @Eric has amazingly solved this problem, THANKS, sent a bounty. Must set Theme.AppCompat.Dialog in manifest. You may only set your own style in onCreate. It was also the answer to my question here: https://stackoverflow.com/a/67045156/294884 – Fattie Apr 14 '21 at 11:17

4 Answers4

32

Background

The Activity behind an Acivity is drawn if the foreground activity's theme according to its AndroidManifest.xml is a dialog; otherwise the android os will not draw the Activity behind it (probably to save memory since it usually won't be seen anyway).

To exploit this, we set the theme of our Acitvity to a dialog in the manifest, making the android os draw the Activity behind it, but later, programatically set our Activity's theme to whatever we like at runtime.

Example on github

I made an example and put it on github.

Tutorial

Step 1: create two custom themes for your application in styles.xml. One for normal activities, and another for dialog activities. It is important for the custom dialog theme to inherit from a base theme that is also a dialog. In my case, the parent theme is Base.Theme.AppCompat.Light.Dialog.FixedSize). Here is my styles.xml:

<resources>

    <!-- custom normal activity theme -->    
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    </style>

    <!-- custom dialog activity theme -->
    <style name="AppTheme.Dialog" parent="Base.Theme.AppCompat.Light.Dialog.FixedSize">
        <!-- removing the dialog's action bar -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

</resources>

Step 2: in the AndroidManifest.xml, set the theme of the Activity in question to any dialog theme. This makes the android os think that the Activity is a dialog, so it will draw the Activity behind it, and not black it out. In my case, I used Theme.AppCompat.Dialog. Below is my AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.eric.questiondialog_artifact">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">
        <activity
            android:name=".DialogActivity"
            android:label="@string/app_name"
            android:theme="@style/Theme.AppCompat.Dialog"> <-- IMPORTANT!!! -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Step 3: in the actual activity, set the theme programatically to either the theme for normal activities, or the theme for dialogs. My DialogActivity.java is below:

package com.example.eric.questiondialog_artifact;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

public class DialogActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        setTheme(R.style.AppTheme_Dialog); // can either use R.style.AppTheme_Dialog or R.style.AppTheme as deined in styles.xml
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog);
    }
}
Eric
  • 16,397
  • 8
  • 68
  • 76
  • Can you check this solution with application target API 27 and above. I got crash with fullscreen theme `Only fullscreen activities can request orientation`. When i set fullscreen is default and change to dialog theme at runtime. The background is black. If dialog theme is preset, the fullscreen is crash – Trung Nguyen Aug 14 '18 at 02:02
  • I just tested this solution on Android Pie (API 28). It seems to work fine without crashing when programmatically starting the Activity as a fullscreen one or dialog one. – Eric Aug 20 '18 at 02:40
  • can you add a sample project on github? Thank you – Trung Nguyen Sep 04 '18 at 08:17
  • 1
    @NamTrung hey, I finally got around to creating [an example for this answer](https://github.com/ericytsang/stackoverflow.35834481/tree/master). – Eric Sep 24 '18 at 22:07
  • Thanks. I'll try your sample – Trung Nguyen Sep 25 '18 at 15:09
  • I forgot to mention that my activity have forced orientation to lanscape. If i add `android:screenOrientation="sensorLandscape"` to `NextActivity`, the app will crash – Trung Nguyen Nov 08 '18 at 08:33
  • I will see if i can create a branch on the repo that has a working solution for this case. I'm not sure if it is possible to do this. – Eric Nov 08 '18 at 12:00
  • how can I setOnDismissListener on activity opened as Dialog? – Riddhi Shah Dec 11 '19 at 06:22
  • @RiddhiShah if the dialog is actually an `Activity`, you can either put some code in the `Activity`'s [`onDestroy`](https://developer.android.com/reference/android/app/Activity#onDestroy()) lifecycle method. Or, you can use the `startActivityForResult` when launching the `Activity` so that you can handle the result in `onActivityResult` (see [Getting a result from an Activity](https://developer.android.com/training/basics/intents/result)) – Eric Dec 16 '19 at 06:35
  • @Eric I am opening my dialog activity whenever I receive a push notification. so I won't be able to startActivityForResult. I gave theme in AndroidManifest like above. – Riddhi Shah Dec 17 '19 at 09:33
  • Hey @RiddhiShah , sorry for the late reply. maybe you can do this: https://stackoverflow.com/a/52788197/2898715 ? and if you want the `onDismissListener` code to only be run when the activity was started from the notification (and not run it if the activity was started from elsewhere) then you can pass in a special flag/parameter into the activity (via the intent you use to start it), and check that flag when checking `isFinishing`, too – Eric Feb 07 '20 at 17:30
  • 1
    For anyone who wants to change the size of the activity, he must delete .FixedSize in the `style` and change the params of the `LinearLayout` – Mohamed Ben Romdhane Nov 30 '20 at 09:28
  • Notice .. https://stackoverflow.com/questions/67041191/updated-to-4-2rc1-and-transparent-activities-do-not-work-suddenly-black – Fattie Apr 11 '21 at 12:26
2

if what you're looking for is just a theme with transparent background for you activity, just use this:

<style name="Theme.Transparent" parent="android:Theme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>

apply this style to your activity in your AndroidManifest file and this is it

ebarault
  • 126
  • 5
0

I am late but still for future users you need to call the below code after setTheme() Calling this allows the Activity behind this one to be seen again. Once all such Activities have been redrawn

// setTheme()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            try {
            Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions");
            getActivityOptions.setAccessible(true);
            Object options = getActivityOptions.invoke(activity);

            Class<?>[] classes = Activity.class.getDeclaredClasses();
            Class<?> translucentConversionListenerClazz = null;
            for (Class clazz : classes) {
                if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
                    translucentConversionListenerClazz = clazz;
                }
            }
            Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent",
                    translucentConversionListenerClazz, ActivityOptions.class);
            convertToTranslucent.setAccessible(true);
            convertToTranslucent.invoke(activity, null, options);
        } catch (Throwable t) {
        }
        } else {
            try {
            Class<?>[] classes = Activity.class.getDeclaredClasses();
            Class<?> translucentConversionListenerClazz = null;
            for (Class clazz : classes) {
                if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
                    translucentConversionListenerClazz = clazz;
                }
            }
            Method method = Activity.class.getDeclaredMethod("convertToTranslucent",
                    translucentConversionListenerClazz);
            method.setAccessible(true);
            method.invoke(activity, new Object[] {
                null
            });
        } catch (Throwable t) {
        }
        }
Shapun
  • 1
  • 2
-1

Try these code before dailog.setMessage(...);

Dialog id  = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_DARK);

Dialog ID = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);

//Default theme 

Try this for Old theme Dialog ID = new AlertDialog.Builder(this,AlertDialog.THEME_TRADITIONAL);

Try these for KITKAT theme

Dialog ID = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_DARK); //Dark


Dialog ID = new AlertDialog.Builder(this,AlertDialog.THEME_HOLO_LIGHT);

Try these codes for Pragmatically

Exmaple

    dialog = new AlertDialog.Builder(this);
            dialog = new AlertDialog.Builder(this,AlertDialog.THEME_DEVICE_DEFAULT_DARK);
            dialog.setTitle("HAI");
            dialog.setMessage("look");
            dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
Toast toast= Toast.makeText(getApplicationContext(), "This is exmaple theme", Toast.LENGTH_LONG);
Hendry leo
  • 5
  • 1
  • 8