46

I'm switching my old Dialogs to DialogFragment, but the themes and styles don't seem to be working.

I'm using the DialogFragment from the compatibility library v4, and in the onCreate method I've tried calling setStyle(style, theme); with a lot of different themes, but the dialog always shows as an "old" dialog in the emulator running Android 4.0.3 (i.e., it does not shows in Holo theme).

Is there anything else that I should be doing? Does using the compatibility library disables the Holo theme or anything? If this is the case, should I create two DialogFragments, one for older versions and one for newer versions?

Thanks!


Here's the (simplified) code for my dialog. I've tried both Theme_Holo_Dialog_NoActionBar and Theme_DeviceDefault_Dialog_NoActionBar, but the Android 4 emulator always shows the dialog as an "old" dialog instead of using the Holo theme. What am I doing wrong? :(

[...]
import android.support.v4.app.DialogFragment;
[...]

public class AlertDialogFragment extends DialogFragment {

  public static AlertDialogFragment newInstance(int id) {

    AlertDialogFragment f = new AlertDialogFragment();
    Bundle args = new Bundle();
    args.putInt("id", id);
    f.setArguments(args);

 }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    int style = DialogFragment.STYLE_NORMAL, theme = 0;
    theme = android.R.style.Theme_Holo_Dialog_NoActionBar;
    setStyle(style, theme);     
  }

  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState) {

    mId = getArguments().getInt("id");
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
        .setTitle(mTitle)
        .setMessage(mMessage)
        .setPositiveButton(getString(R.string.btn_ok), new DialogInterface.OnClickListener() {      
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dismiss();                  
            }
        });
        return builder.create();
    }
luthier
  • 2,674
  • 4
  • 32
  • 35
  • What style are you inheriting from, show us styles.xml also what is your targetSdk? it needs to be over 11 – Blundell May 14 '12 at 21:21
  • I'm targeting SDK 14, and I'm not even using a styles.xml file, I'm just calling setStyle(style, theme); in the onCreate method of the DialogFragment trying multiple combinations of style and theme. For example, in my "old" dialog I used android.R.style.Theme_DeviceDefault_Dialog_NoActionBar and it showed as Holo in the ICS emulator, but now using the same theme it doesn't. – luthier May 15 '12 at 07:39
  • So I thought the docs said don't override onCreate AND onCreateDialog because you get weird behaviour. Also I can't see where you are actually setting the theme anywhere – Blundell May 16 '12 at 19:13
  • I'm sorry, I somehow deleted the setStyle call when I pasted the code. But it was there, I promise :) [and it's there now] On the other hand, the only thing that I saw in the docs was that there's no need for onCreateView if you are using onCreateDialog, but nothing about onCreate. If this is the case, could you please tell me where you saw it? Thanks! – luthier May 17 '12 at 07:11
  • Yeah your right I got onCreate and onCreateView mixed up – Blundell May 18 '12 at 13:56
  • Related: https://stackoverflow.com/q/30854069/1531971 –  Feb 01 '19 at 18:27

5 Answers5

49

You shoudn't use the AlertDialog.Builder(Context, int) constructor with the support library because it is only available since API 11.

To setup a theme to your dialog, use instead a ContextThemeWrapper like this:

ContextThemeWrapper context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Dialog_NoActionBar);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
Florian
  • 491
  • 1
  • 4
  • 3
  • 5
    Has anyone tried this with custom styles? When I pass in a predefined android style it works, but not if I pass in my own style.. (my custom style is a child of Theme.Dialog) – ashutosh Feb 27 '13 at 10:35
  • If you don't use the builder at all an alternative way (which worked for me with custom styles) is given: http://stackoverflow.com/questions/13469084/dialogfragment-in-android-with-theme – Almer Mar 27 '13 at 12:46
31

I believe you need to set the theme on the actual Dialog and not the Fragment

Use this constructor to create your AlertDialog:

 AlertDialog.Builder(Context context, int theme)

ie

 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), theme)
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • Not exactly... in the end I created different XML layout files for each Android version, and that seemed to do the trick... – luthier Aug 06 '12 at 07:49
  • That and using the theme AlertDialog.THEME_DEVICE_DEFAULT_LIGHT instead of android.R.style.Theme_Holo_Dialog_NoActionBar :) – luthier Sep 25 '12 at 17:02
  • @Blundell I was getting the theme but along with an extra background which I dont want. Below solution worked for me. `ContextThemeWrapper context = new ContextThemeWrapper( getActivity(), theme);` `AlertDialog.Builder builder = new AlertDialog.Builder(context);` – Bharat Dodeja Jul 04 '13 at 13:52
  • @Blundell thanks a bunch man, saved me from creating a custom dialog layout! (even though I'll probably do that in the end sigh) – Vedran Kopanja Apr 19 '14 at 17:16
  • 5
    Warning: If you're using .setView() as well, you must get the LayoutInflater from the same wrapped context by calling `getSystemService(Context.LAYOUT_INFLATER_SERVICE)` for the theme to be applied there as well. Wasted 2 hours to find that out. – Nilzor Oct 13 '14 at 14:33
  • 3
    The dialog gets created automatically on the DialogFragment class, how do get access to the builder – frankelot Dec 21 '15 at 23:42
23

I just lost a lot of time to this, but I finally found a way to do this entirely in xml.

In an application theme, Dialogs are actually themed separately. So to style all DialogFragments with green buttons and green EditText hints, you would make a style like this:

<style name="DialogTheme" parent="@android:style/Theme.Holo.Light.Dialog">
    <item name="android:buttonStyle">@style/button_green</item>
    <item name="android:textColorHint">@color/green</item>
</style>

Then add this theme to your application theme as the dialogTheme

<style name="MyTheme" parent="android:Theme.Holo.Light">
    <item name="android:dialogTheme">@style/DialogTheme</item>
</style>

Many thanks to whoever wrote this post for showing me the path to what I'd been searching for!

pumpkinpie65
  • 960
  • 2
  • 14
  • 16
  • 1
    it's ok. but how could I use `DialogFragment.setStyle` for choosing style at runtime? – fatfatson May 27 '19 at 11:02
  • @fatfatson you need to apply the setStyle in onCreate. Neither in constructor, nor in onCreateView. Or even better, just override getTheme() with whatever style you want. – Pavitra Kansara Oct 30 '19 at 21:50
2

Here is a more current answer, using target SDK of 23 and min SDK of 14, this code works perfectly for me.

The main change from the code in the question is setting the theme in the constructor, only overriding onCreateDialog(), and using the AlertDialog class from the v7 support library.

Using this code, the green text flat (borderless) buttons are shown on 4.4.4 as opposed to the default gray buttons with borders.

import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.support.v4.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;

public class MyDialog extends DialogFragment {

    String message;

    public MyDialog(String m) {
        message = m;
        int style = DialogFragment.STYLE_NORMAL, theme = 0;
        theme = android.R.style.Theme_Holo_Dialog_NoActionBar;
        setStyle(style, theme);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        return new AlertDialog.Builder(getActivity())
                .setMessage(message)
                .setPositiveButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((EnterPhoneNumberActivity)getActivity()).doPositiveClick();
                        }
                    }
                )
                .setNegativeButton("EDIT",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((EnterPhoneNumberActivity)getActivity()).doNegativeClick();
                        }
                    }
                )
                .create();
    }
}

Usage in an AppCompatActivity:

    String message = "test";
    if (message != null) {
        DialogFragment newFragment = new MyDialog(message);
        newFragment.show(getSupportFragmentManager(), "dialog");
    }
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
-4

You should write these codes in "onCreateView".

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    View view = inflater.inflate(R.layout.dialog_your_theme, container);
    return view;
}
  • While this code block may answer the question, it would be best if you could provide a little explanation for why it does so. – David Mar 20 '15 at 09:11