Comment changer de thème pour AlertDialog


242

Je me demandais si quelqu'un pouvait m'aider. J'essaie de créer un AlertDialog personnalisé. Pour ce faire, j'ai ajouté la ligne de code suivante dans styles.xml

<resources>
 <style name="CustomAlertDialog" parent="android:Theme.Dialog.Alert">
  <item name="android:windowBackground">@drawable/color_panel_background</item>
 </style>
</resources>
  • color_panel_background.9.png se trouve dans le dossier drawable. Ceci est également disponible dans le dossier res du SDK Android.

Voici l'activité principale.

package com.customdialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;

public class CustomDialog extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.setTheme(R.style.CustomAlertDialog);
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("HELLO!");
        builder .setCancelable(false)
          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               //MyActivity.this.finish();
           }
       })
       .setNegativeButton("No", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               //dialog.cancel();
           }
       });

        AlertDialog alertdialog = builder.create();
        alertdialog.show();
    }
}

Afin d'appliquer le thème à un AlertDialog, j'ai dû mettre le thème dans le contexte actuel.

Cependant, je n'arrive pas à obtenir l'application pour afficher AlertDialog personnalisé. Quelqu'un peut-il m'aider avec ça?



J'ai trouvé ce dépôt sur github très utile: github.com/StylingAndroid/AlertDialog
esilver

Réponses:


363

Dans Dialog.java (Android src), un ContextThemeWrapper est utilisé. Vous pouvez donc copier l'idée et faire quelque chose comme:

AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom));

Et puis coiffez-le comme vous le souhaitez:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AlertDialogCustom" parent="@android:style/Theme.Dialog">
        <item name="android:textColor">#00FF00</item>
        <item name="android:typeface">monospace</item>
        <item name="android:textSize">10sp</item>
    </style>
</resources>

62
N'utilisez pas @android: style / AlertDialog. Ce n'est pas dans l'API publique. Par conséquent, dans Android 2.3.3, il se bloque lors de la création du générateur.
Catalin Morosan

18
@kaciula Est @android:style/Theme.Dialogpublic? Peut-il être utilisé à la place?
HRJ

24
Oui. C'est public. Consultez developer.android.com/reference/android/R.style.html pour une liste de tous les styles publics. Gardez à l'esprit que la dénomination dans l'API est différente de celle utilisée dans le code. Il y a un '_' au lieu de "." (Theme_Dialog)
Catalin Morosan

2
Où dois-je placer le fichier xml ci-dessus?
Chaitanya Chandurkar

3
Pour un thème plus récent faisant partie des thèmes de compatibilité, je suggère d'utiliser le Theme.AppCompat.Light.Dialog.Alertstyle en tant que parent de votre style personnalisé. Mais si vous faites cela, assurez-vous que vous importez import android.support.v7.app.AlertDialog; et nonimport android.app.AlertDialog
w3bshark

93

J'avais ce AlertDialogproblème lié au thème en utilisant sdk 1.6 comme décrit ici: http://markmail.org/message/mj5ut56irkrkc4nr

J'ai résolu le problème en procédant comme suit:

  new AlertDialog.Builder(
  new ContextThemeWrapper(context, android.R.style.Theme_Dialog))

J'espère que cela t'aides.


2
Il existe plusieurs thèmes pertinents; dans mon cas, android.R.style.Theme_Holo_Dialog était mieux adapté. Bon conseil.
Johnny O

78

J'ai écrit un article dans mon blog sur la façon de configurer la disposition d'un AlertDialog avec des fichiers de style XML. Le problème principal est que vous avez besoin de différentes définitions de style pour différents paramètres de disposition. Voici un passe-partout basé sur le style AlertDialog de Holo Light Platform version 19 pour un fichier de style qui devrait couvrir un tas d'aspects de mise en page standard tels que les tailles de texte et les couleurs d'arrière-plan.

<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
    ...
    <item name="android:alertDialogTheme">@style/MyAlertDialogTheme</item>
    <item name="android:alertDialogStyle">@style/MyAlertDialogStyle</item>
    ...
</style>

<style name="MyBorderlessButton">
    <!-- Set background drawable and text size of the buttons here -->
    <item name="android:background">...</item>
    <item name="android:textSize">...</item>
</style>

<style name="MyButtonBar">
    <!-- Define a background for the button bar and a divider between the buttons here -->
    <item name="android:divider">....</item>
    <item name="android:dividerPadding">...</item>
    <item name="android:showDividers">...</item>
    <item name="android:background">...</item>
</style>

<style name="MyAlertDialogTitle">
    <item name="android:maxLines">1</item>
    <item name="android:scrollHorizontally">true</item>
</style>

<style name="MyAlertTextAppearance">
    <!-- Set text size and color of title and message here -->
    <item name="android:textSize"> ... </item>
    <item name="android:textColor">...</item>
</style>

<style name="MyAlertDialogTheme">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowTitleStyle">@style/MyAlertDialogTitle</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:textAppearanceMedium">@style/MyAlertTextAppearance</item>
    <!-- If you don't want your own button bar style use
            @android:style/Holo.Light.ButtonBar.AlertDialog
            and
            ?android:attr/borderlessButtonStyle
         instead of @style/MyButtonBar and @style/MyBorderlessButton -->
    <item name="android:buttonBarStyle">@style/MyButtonBar</item>
    <item name="android:buttonBarButtonStyle">@style/MyBorderlessButton</item>
</style>

<style name="MyAlertDialogStyle">
    <!-- Define background colors of title, message, buttons, etc. here -->
    <item name="android:fullDark">...</item>
    <item name="android:topDark">...</item>
    <item name="android:centerDark">...</item>
    <item name="android:bottomDark">...</item>
    <item name="android:fullBright">...</item>
    <item name="android:topBright">...</item>
    <item name="android:centerBright">...</item>
    <item name="android:bottomBright">...</item>
    <item name="android:bottomMedium">...</item>
    <item name="android:centerMedium">...</item>
</style>

2
puis-je vous demander pourquoi nous avons tous deux besoin de style et de thème pour la personnalisation AlertDialog? Merci beaucoup! @nantoka
brainvision

2
@brainvision Mon entrée de blog contient les détails, mais en bref, la disposition d'un AlertDialog provient de deux classes différentes (Dialog et AlertController) qui utilisent des fichiers de paramètres de disposition différents.
Nantoka du

46
 <style name="AlertDialogCustom" parent="Theme.AppCompat.Light.Dialog.Alert">
    <!-- Used for the buttons -->
    <item name="colorAccent">@color/colorAccent</item>
    <!-- Used for the title and text -->
    <item name="android:textColorPrimary">#FFFFFF</item>
    <!-- Used for the background -->
    <item name="android:background">@color/teal</item>
</style>





new AlertDialog.Builder(new ContextThemeWrapper(context,R.style.AlertDialogCustom))
            .setMessage(Html.fromHtml(Msg))
            .setPositiveButton(posBtn, okListener)
            .setNegativeButton(negBtn, null)
            .create()
            .show();

3
La solution la plus simpliste, mais rapide!
FonzTech

4
OK, que diriez-vous d'utiliser un attribut pour le déclarer globalement dans "AppTheme"?
deadfish

2
Cela m'a aidé à changer les couleurs des boutons de la boîte de dialogue.
icarovirtual

1
Merci mon mec, tu as sauvé ma semaine !!
Clifton Steenkamp

31

J'avais du mal avec cela - vous pouvez styliser l'arrière-plan de la boîte de dialogue à l'aide android:alertDialogStyle="@style/AlertDialog"de votre thème, mais il ignore tous les paramètres de texte que vous avez. Comme @rflexor l'a dit ci-dessus, cela ne peut pas être fait avec le SDK avant Honeycomb (vous pouvez bien l'utiliser Reflection).

Ma solution, en un mot, a été de styliser l'arrière-plan de la boîte de dialogue à l'aide de ce qui précède, puis de définir un titre et une vue de contenu personnalisés (en utilisant des mises en page identiques à celles du SDK).

Mon emballage:

import com.mypackage.R;

import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class CustomAlertDialogBuilder extends AlertDialog.Builder {

    private final Context mContext;
    private TextView mTitle;
    private ImageView mIcon;
    private TextView mMessage;

    public CustomAlertDialogBuilder(Context context) {
        super(context);
        mContext = context; 

        View customTitle = View.inflate(mContext, R.layout.alert_dialog_title, null);
        mTitle = (TextView) customTitle.findViewById(R.id.alertTitle);
        mIcon = (ImageView) customTitle.findViewById(R.id.icon);
        setCustomTitle(customTitle);

        View customMessage = View.inflate(mContext, R.layout.alert_dialog_message, null);
        mMessage = (TextView) customMessage.findViewById(R.id.message);
        setView(customMessage);
    }

    @Override
    public CustomAlertDialogBuilder setTitle(int textResId) {
        mTitle.setText(textResId);
        return this;
    }
    @Override
    public CustomAlertDialogBuilder setTitle(CharSequence text) {
        mTitle.setText(text);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setMessage(int textResId) {
        mMessage.setText(textResId);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setMessage(CharSequence text) {
        mMessage.setText(text);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setIcon(int drawableResId) {
        mIcon.setImageResource(drawableResId);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setIcon(Drawable icon) {
        mIcon.setImageDrawable(icon);
        return this;
    }

}

alert_dialog_title.xml (extrait du SDK)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
    <LinearLayout
            android:id="@+id/title_template"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical"
            android:layout_marginTop="6dip"
            android:layout_marginBottom="9dip"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip">

            <ImageView android:id="@+id/icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:paddingTop="6dip"
                android:paddingRight="10dip"
                android:src="@drawable/ic_dialog_alert" />
            <TextView android:id="@+id/alertTitle"
                style="@style/?android:attr/textAppearanceLarge"
                android:singleLine="true"
                android:ellipsize="end"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
        <ImageView android:id="@+id/titleDivider"
            android:layout_width="fill_parent"
            android:layout_height="1dip"
            android:scaleType="fitXY"
            android:gravity="fill_horizontal"
            android:src="@drawable/divider_horizontal_bright" />
</LinearLayout>

alert_dialog_message.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/scrollView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingTop="2dip"
            android:paddingBottom="12dip"
            android:paddingLeft="14dip"
            android:paddingRight="10dip">
    <TextView android:id="@+id/message"
                style="?android:attr/textAppearanceMedium"
                android:textColor="@color/dark_grey"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:padding="5dip" />
</ScrollView>

Ensuite, utilisez simplement CustomAlertDialogBuilderau lieu de AlertDialog.Builderpour créer vos boîtes de dialogue, puis appelez setTitleet setMessagecomme d'habitude.


3
comment avez-vous accédé à android.R.internal.id.alerttitle?
Gilbert

2
Je ne l'ai pas fait, j'ai accédé à R.id.alertTitle
Joseph Earl

28

Vous pouvez attribuer directement un thème lorsque vous lancez le générateur:

AlertDialog.Builder builder = new AlertDialog.Builder(
                    getActivity(), R.style.MyAlertDialogTheme);

Personnalisez ensuite votre thème dans votre values/styles.xml

<!-- Alert Dialog -->
<style name="MyAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:colorBackground">@color/alertDialogBackground</item>
    <item name="android:windowBackground">@color/alertDialogBackground</item>
</style>

1
Parfait. La seule chose que j'ai utiliséeTheme.AppCompat.Light.Dialog.Alert
ekashking

11

Pour la boîte de dialogue personnalisée:

il suffit d'appeler super(context,R.style.<dialog style>)au lieu de super(context)dans le constructeur de dialogue

public class MyDialog extends Dialog
{
    public MyDialog(Context context)
    {
       super(context, R.style.Theme_AppCompat_Light_Dialog_Alert)
    }
}


Pour AlertDialog:

Créez simplement alertDialog avec ce constructeur:

 new AlertDialog.Builder(
 new ContextThemeWrapper(context, android.R.style.Theme_Dialog))

1
Pas besoin d'étendre Dialog avec une nouvelle classe vide, car il existe déjà une version constructeur qui prend le style du thème.
FindOut_Quran

@FindOut_Quran Le but est de montrer comment remplacer le style dans une classe de dialogue personnalisée. C'est juste un exemple, votre vraie classe Dialog contiendra également un autre code.
Niall

8

Je suppose que cela ne peut pas être fait. Du moins pas avec le Builder. Je travaille avec 1.6 et l'implémentation dans Builder.create () est:

public AlertDialog create() {
    final AlertDialog dialog = new AlertDialog(P.mContext);
    P.apply(dialog.mAlert);
    [...]
}

qui appelle le constructeur "not-theme-aware" de AlertDialog, qui ressemble à ceci:

protected AlertDialog(Context context) {
    this(context, com.android.internal.R.style.Theme_Dialog_Alert);
}

Il existe un deuxième constructeur dans AlertDialog pour changer les thèmes:

protected AlertDialog(Context context, int theme) {
    super(context, theme);
    [...]
}

que le Builder n'appelle tout simplement pas.

Si la boîte de dialogue est assez générique de toute façon, j'essaierais d'écrire une sous-classe d'AlertDialog, d'appeler le deuxième constructeur et d'utiliser cette classe à la place du mécanisme Builder.


4

Un meilleur moyen de le faire est d'utiliser une boîte de dialogue personnalisée et de personnaliser selon vos besoins. Voici un exemple de boîte de dialogue personnalisée .....

entrez la description de l'image ici

public class CustomDialogUI {
Dialog dialog;
Vibrator vib;
RelativeLayout rl;

@SuppressWarnings("static-access")
public void dialog(final Context context, String title, String message,
        final Runnable task) {
    dialog = new Dialog(context);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.custom);
    dialog.setCancelable(false);
    TextView m = (TextView) dialog.findViewById(R.id.message);
    TextView t = (TextView) dialog.findViewById(R.id.title);
    final Button n = (Button) dialog.findViewById(R.id.button2);
    final Button p = (Button) dialog.findViewById(R.id.next_button);
    rl = (RelativeLayout) dialog.findViewById(R.id.rlmain);
    t.setText(bold(title));
    m.setText(message);
    dialog.show();
    n.setText(bold("Close"));
    p.setText(bold("Ok"));
    // color(context,rl);
    vib = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
    n.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            vib.vibrate(15);
            dialog.dismiss();
        }
    });
    p.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            vib.vibrate(20);
            dialog.dismiss();
            task.run();
        }
    });
}
 //customize text style bold italic....
public SpannableString bold(String s) {
    SpannableString spanString = new SpannableString(s);
    spanString.setSpan(new StyleSpan(Typeface.BOLD), 0,
            spanString.length(), 0);
    spanString.setSpan(new UnderlineSpan(), 0, spanString.length(), 0);
    // spanString.setSpan(new StyleSpan(Typeface.ITALIC), 0,
    // spanString.length(), 0);
    return spanString;
}

}

Voici la disposition xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
>

<RelativeLayout
    android:id="@+id/rlmain"
    android:layout_width="fill_parent"
    android:layout_height="150dip"
    android:layout_alignParentLeft="true"
    android:layout_centerVertical="true"
    android:background="#569CE3" >

    <RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="25dip"
        android:layout_marginTop="10dip" >

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:text="Are you Sure?"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="#ffffff"
            android:textSize="13dip" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relativeLayout2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/relativeLayout1"
        android:layout_alignRight="@+id/relativeLayout1"
        android:layout_below="@+id/relativeLayout1"
        android:layout_marginTop="5dip" >
    </RelativeLayout>

    <ProgressBar
        android:id="@+id/process"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="3dip"
        android:layout_marginTop="3dip" />

    <RelativeLayout
        android:id="@+id/relativeLayout3"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/relativeLayout2"
        android:layout_below="@+id/relativeLayout2"
        android:layout_toLeftOf="@+id/process" >

        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="#ffffff"
            android:textSize="13dip"/>

    </RelativeLayout>

    <Button
        android:id="@+id/next_button"
        android:layout_width="90dip"
        android:layout_height="35dip"
        android:layout_alignParentBottom="true"
        android:textColor="@drawable/button_text_color"
         android:background="@drawable/blue_button"
         android:layout_marginBottom="5dp"
           android:textSize="10dp"

        android:layout_alignRight="@+id/relativeLayout3"
        android:text="Okay" />

    <Button
        android:id="@+id/button2"
        android:text="Cancel"
        android:textColor="@drawable/button_text_color"
        android:layout_width="90dip"
        android:layout_height="35dip"
        android:layout_marginBottom="5dp"
         android:background="@drawable/blue_button"
         android:layout_marginRight="7dp"
        android:textSize="10dp"
        android:layout_alignParentBottom="true"
        android:layout_toLeftOf="@+id/next_button"
         />

</RelativeLayout>


7
Thématiser et utiliser une vue personnalisée sont deux choses différentes et ont des objectifs différents.
jmc34

3

Quiconque essaie de le faire dans un fragment (en utilisant la bibliothèque de support, c'est-à-dire pré API 11) devrait aller avec ceci:

public class LoadingDialogFragment extends DialogFragment {
    public static final String ID = "loadingDialog";

    public static LoadingDialogFragment newInstance() {
        LoadingDialogFragment f = new LoadingDialogFragment();

        return f;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        StyleAlertDialog adb = new StyleAlertDialog(getActivity(), R.style.Your_Style);
        adb.setView(getActivity().getLayoutInflater().inflate(R.layout.fragment_dialog_layout, null));
        return adb;
    }

    private class StyleAlertDialog extends AlertDialog {
        protected StyleAlertDialog(Context context, int theme) {
            super(context, theme);
        }
    }
}

@Rflexor m'a donné le coup de pouce pour étendre AlertDialog et exposer le constructeur grâce


Le constructeur AlertDialog.Builder(Context, int)ne fonctionne que sur l'API 11 et au-dessus. Votre code se bloquera sur les versions antérieures d'Android.
Joseph Earl

@JosephEarl (en utilisant la bibliothèque de support, c'est-à-dire avant l'API 11)
Blundell

Mon mauvais, vous utilisez le constructeur de dialogue et non le constructeur de constructeur de dialogue.
Joseph Earl

2

La solution d'Arve Waltin semble bonne, même si je ne l'ai pas encore testée. Il y a une autre solution dans le cas où vous avez du mal à obtenir que le travail .... Extend AlertDialog.Builderet passer outre toutes les méthodes (par exemple. setText, setTitle,setView , Etc.) pour ne pas définir le véritable texte de dialogue / titre / vue, mais de créer une nouvelle vue à l' intérieur la vue de la boîte de dialogue fait tout là-dedans. Ensuite, vous êtes libre de tout coiffer à votre guise.

Pour clarifier, en ce qui concerne la classe parente, la vue est définie, et rien d'autre.

En ce qui concerne votre classe étendue personnalisée, tout se fait dans cette vue.


0

Je ne sais pas comment la solution d'Arve fonctionnerait dans une boîte de dialogue personnalisée avec un générateur où la vue est gonflée via un LayoutInflator.

La solution devrait être d'insérer le ContextThemeWrapper dans le gonfleur à travers cloneInContext():

View sensorView = LayoutInflater.from(context).cloneInContext(
     new ContextThemeWrapper(context, R.style.AppTheme_DialogLight)
).inflate(R.layout.dialog_fingerprint, null);

-1

Cela peut être fait simplement en utilisant setView () du Builder. Vous pouvez créer n'importe quelle vue de votre choix et alimenter le générateur. Cela fonctionne bien. J'utilise un TextView personnalisé qui est rendu par le générateur de boîtes de dialogue. Je ne mets pas le message et cet espace est utilisé pour rendre ma vue textuelle personnalisée.


-12
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title");
builder.setMessage("Description");
builder.setPositiveButton("OK", null);
builder.setNegativeButton("Cancel", null);
builder.show();

Cela vous dérange de formater votre code avec l'extrait de code intégré?
Adriano
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.