Cómo cambiar el tema de AlertDialog

242

Me preguntaba si alguien podría ayudarme. Estoy tratando de crear un AlertDialog personalizado. Para hacer esto, agregué la siguiente línea de código en 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 encuentra en la carpeta dibujable. Esto también está disponible en la carpeta de Android SDK res.

La siguiente es la actividad principal.

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();
    }
}

Para aplicar el tema a un AlertDialog, tuve que establecer el tema en el contexto actual.

Sin embargo, parece que no puedo hacer que la aplicación muestre AlertDialog personalizado. ¿Puede alguien ayudarme con esto?

Min Soo Kim
fuente
Encontré este repositorio en github muy útil: github.com/StylingAndroid/AlertDialog
esilver

Respuestas:

363

En Dialog.java (Android src) se usa un ContextThemeWrapper. Entonces podría copiar la idea y hacer algo como:

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

Y luego dale el estilo que quieras:

<?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>
Arve Waltin
fuente
62
No use @android: style / AlertDialog. No está en la API pública. Como consecuencia, en Android 2.3.3, se bloquea al crear el generador.
Catalin Morosan
18
@kaciula ¿Es @android:style/Theme.Dialogpúblico? ¿Se puede usar en su lugar?
HRJ
24
Si. Es público Consulte developer.android.com/reference/android/R.style.html para obtener una lista de todos los estilos públicos. Tenga en cuenta que los nombres en la API son diferentes a los utilizados en el código. Hay un '_' en lugar de "." (Theme_Dialog)
Catalin Morosan
2
¿Dónde debo colocar el archivo xml anterior?
Chaitanya Chandurkar
3
Para un tema más nuevo que sea parte de los temas de compatibilidad, sugeriría usar el Theme.AppCompat.Light.Dialog.Alertestilo como padre de su estilo personalizado. Pero, si haces esto, asegúrate de importar import android.support.v7.app.AlertDialog; y noimport android.app.AlertDialog
w3bshark
93

Estaba teniendo este AlertDialogproblema relacionado con el tema usando sdk 1.6 como se describe aquí: http://markmail.org/message/mj5ut56irkrkc4nr

Resolví el problema haciendo lo siguiente:

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

Espero que esto ayude.

chee
fuente
2
Hay varios temas relevantes; en mi caso, android.R.style.Theme_Holo_Dialog fue mejor Gran consejo
Johnny O
78

He escrito un artículo en mi blog sobre cómo configurar el diseño de un AlertDialog con archivos de estilo XML. El principal problema es que necesita diferentes definiciones de estilo para diferentes parámetros de diseño. Aquí hay un resumen basado en el estilo AlertDialog de Holo Light Platform versión 19 para un archivo de estilo que debe cubrir un montón de aspectos de diseño estándar como tamaños de texto y colores de fondo.

<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>
Nantoka
fuente
2
¿podría preguntarle por qué ambos necesitamos estilo y tema para la personalización de AlertDialog? ¡Muchas gracias! @nantoka
brainvision
2
@brainvision Mi entrada de blog tiene los detalles, pero en pocas palabras, el diseño de un AlertDialog proviene de dos clases diferentes (Dialog y AlertController) que utilizan diferentes archivos de parámetros de diseño.
Nantoka
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();
Sai Gopi N
fuente
3
¡La solución más simple pero rápida!
FonzTech
44
OK, ¿qué tal si usamos algún atributo para declararlo globalmente en "AppTheme"?
deadfish
2
Esto me ayudó a cambiar los colores de los botones del diálogo.
icarovirtual
1
¡Gracias amigo, me salvaste la semana!
Clifton Steenkamp
31

Estaba luchando con esto: puede diseñar el fondo del diálogo utilizando android:alertDialogStyle="@style/AlertDialog"su tema, pero ignora cualquier configuración de texto que tenga. Como @rflexor dijo anteriormente, no se puede hacer con el SDK antes de Honeycomb (bueno, podría usarlo Reflection).

Mi solución, en pocas palabras, fue diseñar el fondo del diálogo usando lo anterior, luego establecer un título personalizado y una vista de contenido (usando diseños que sean los mismos que en el SDK).

Mi envoltura:

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 (tomado del 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>

Luego, solo use en CustomAlertDialogBuilderlugar de AlertDialog.Buildercrear sus cuadros de diálogo, y simplemente llame setTitley setMessagecomo de costumbre.

Joseph Earl
fuente
3
¿Cómo accediste a android.R.internal.id.alerttitle?
Gilbert
2
No lo hice, accedí a R.id.alertTitle
Joseph Earl el
28

Puede asignar un tema directamente cuando inicia el Generador:

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

Luego personaliza tu tema en tu 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>
Pha
fuente
1
Perfecto. Lo único que uséTheme.AppCompat.Light.Dialog.Alert
ekashking
11

Para cuadros de diálogo personalizados:

simplemente llame en super(context,R.style.<dialog style>)lugar de super(context)en el constructor de diálogo

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


Para AlertDialog:

Simplemente cree alertDialog con este constructor:

 new AlertDialog.Builder(
 new ContextThemeWrapper(context, android.R.style.Theme_Dialog))
Amir Hossein Ghasemi
fuente
1
No es necesario extender Dialog con una nueva clase vacía, ya que ya existe una versión de constructor que toma el estilo del tema.
FindOut_Quran
@FindOut_Quran El objetivo es mostrar cómo anular el estilo en una clase de diálogo personalizada. Es solo un ejemplo, su clase de diálogo real también tendrá algún otro código.
Niall
8

Supongo que no se puede hacer. Al menos no con el constructor. Estoy trabajando con 1.6 y la implementación en Builder.create () es:

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

que llama al constructor "no consciente del tema" de AlertDialog, que se ve así:

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

Hay un segundo constructor en AlertDialog para cambiar temas:

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

que el constructor simplemente no llama.

Si el Diálogo es bastante genérico de todos modos, intentaría escribir una subclase de AlertDialog, llamando al segundo constructor y usaría esa clase en lugar del mecanismo Builder.

rflexor
fuente
4

Una mejor manera de hacer esto es usar un cuadro de diálogo personalizado y personalizarlo de acuerdo a sus necesidades aquí es un ejemplo de cuadro de diálogo personalizado .....

ingrese la descripción de la imagen aquí

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;
}

}

Aquí está el diseño 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>


fuente
77
El tema y el uso de una vista personalizada son 2 cosas diferentes y tienen diferentes propósitos.
jmc34
3

Cualquiera que intente hacer esto dentro de un Fragmento (usando la biblioteca de soporte, es decir, antes de la API 11) debería ir con esto:

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 me dio un empujón para extender AlertDialog y exponer al constructor gracias

Blundell
fuente
El constructor AlertDialog.Builder(Context, int)solo funciona en API 11 y superior. Su código se bloqueará en versiones anteriores de Android.
Joseph Earl
@JosephEarl (usando la biblioteca de soporte, es decir, pre API 11)
Blundell
Lo malo es que usas el constructor de diálogo y no el constructor de diálogo.
Joseph Earl
2

La solución de Arve Waltin se ve bien, aunque todavía no la he probado. Hay otra solución en caso de tener problemas para conseguir que el trabajo .... Extender AlertDialog.Buildery reemplazar todos los métodos (por ejemplo. setText, setTitle, setView, Etc) no establecer el actual texto / título / punto de vista de diálogo, sino para crear una nueva vista dentro de la Vista del diálogo hace todo lo que está allí. Entonces eres libre de diseñar todo lo que quieras.

Para aclarar, en lo que respecta a la clase padre, se establece la Vista y nada más.

En lo que respecta a su clase extendida personalizada, todo se hace dentro de esa vista.

Steven L
fuente
0

No estoy seguro de cómo funcionaría la solución de Arve en un cuadro de diálogo personalizado con el generador donde la vista se infla a través de un LayoutInflator.

La solución debe ser insertar el ContextThemeWrapper en el inflador a través de cloneInContext():

View sensorView = LayoutInflater.from(context).cloneInContext(
     new ContextThemeWrapper(context, R.style.AppTheme_DialogLight)
).inflate(R.layout.dialog_fingerprint, null);
6rquídea
fuente
-1

Se puede hacer simplemente usando setView () del generador. Puede crear cualquier vista de su elección y alimentar el generador. Esto funciona bien Yo uso un TextView personalizado que es representado por el generador de diálogo. No configuro el mensaje y este espacio se utiliza para representar mi vista de texto personalizada.

AKh
fuente
-12
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title");
builder.setMessage("Description");
builder.setPositiveButton("OK", null);
builder.setNegativeButton("Cancel", null);
builder.show();
Sanchit Panchwatikar
fuente
¿Le importaría formatear su código con el fragmento de código incorporado?
Adriano