how to programatically theme an activity to be like a dialog?
Asked Answered
U

4

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.

Unscrew answered 7/3, 2016 at 0:42 Comment(3)
Possibly duplicate: #1979869. May be you can also interested in this: github.com/pingpongboss/StandOutRosenberger
@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 https://mcmap.net/q/107951/-android-activity-as-a-dialog, 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.Unscrew
@Unscrew 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://mcmap.net/q/111810/-updated-to-4-2rc1-and-transparent-activities-do-not-work-suddenly-blackPomfret
U
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);
    }
}
Unscrew answered 10/3, 2016 at 11:53 Comment(13)
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 crashGupta
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.Unscrew
can you add a sample project on github? Thank youGupta
@NamTrung hey, I finally got around to creating an example for this answer.Unscrew
Thanks. I'll try your sampleGupta
I forgot to mention that my activity have forced orientation to lanscape. If i add android:screenOrientation="sensorLandscape" to NextActivity, the app will crashGupta
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.Unscrew
how can I setOnDismissListener on activity opened as Dialog?Paresthesia
@RiddhiShah if the dialog is actually an Activity, you can either put some code in the Activity's 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)Unscrew
@Unscrew 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.Paresthesia
Hey @RiddhiShah , sorry for the late reply. maybe you can do this: https://mcmap.net/q/111811/-how-to-know-activity-has-been-finished ? 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, tooUnscrew
For anyone who wants to change the size of the activity, he must delete .FixedSize in the style and change the params of the LinearLayoutAnti
Notice .. #67041691Pomfret
S
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

Stendhal answered 20/1, 2017 at 10:36 Comment(0)
C
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) {
        }
        }
Cruet answered 19/2, 2021 at 17:52 Comment(0)
G
-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);
Gambier answered 6/12, 2017 at 14:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.