Come cambiare tema per AlertDialog


242

Mi chiedevo se qualcuno potesse aiutarmi. Sto cercando di creare un AlertDialog personalizzato. Per fare ciò, ho aggiunto la seguente riga di codice in 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 si trova nella cartella estraibile. Questo è disponibile anche nella cartella res dell'SDK di Android.

Di seguito è l'attività 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();
    }
}

Per applicare il tema a un AlertDialog, ho dovuto impostare il tema sul contesto corrente.

Tuttavia, non riesco proprio a far sì che l'app mostri AlertDialog personalizzato. Qualcuno può darmi una mano con questo?



Ho trovato questo repository su github molto utile: github.com/StylingAndroid/AlertDialog
esilver

Risposte:


363

In Dialog.java (Android src) viene utilizzato un ContextThemeWrapper. Quindi potresti copiare l'idea e fare qualcosa del tipo:

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

E poi lo stile come vuoi:

<?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
Non usare @android: style / AlertDialog. Non è nell'API pubblica. Di conseguenza, in Android 2.3.3 si arresta in modo anomalo durante la creazione del builder.
Catalin Morosan,

18
@kaciula È @android:style/Theme.Dialogpubblico? Può essere usato invece?
HRJ

24
Sì. È pubblico. Dai un'occhiata a developer.android.com/reference/android/R.style.html per un elenco di tutti gli stili pubblici. Tieni presente che la denominazione nell'API è diversa da quella utilizzata nel codice. C'è un '_' invece di "." (Theme_Dialog)
Catalin Morosan,

2
Dove devo posizionare il file XML sopra?
Chaitanya Chandurkar,

3
Per un tema più recente che fa parte dei temi di compatibilità, suggerirei di utilizzare lo Theme.AppCompat.Light.Dialog.Alertstile come genitore del tuo stile personalizzato. Ma, se lo fai, assicurati di importare import android.support.v7.app.AlertDialog; e nonimport android.app.AlertDialog
w3bshark,

93

Stavo riscontrando questo AlertDialogproblema relativo al tema usando sdk 1.6 come descritto qui: http://markmail.org/message/mj5ut56irkrkc4nr

Ho risolto il problema procedendo come segue:

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

Spero che questo ti aiuti.


2
Esistono diversi temi rilevanti; nel mio caso android.R.style.Theme_Holo_Dialog si adattava meglio. Ottimo consiglio
Johnny O

78

Nel mio blog ho scritto un articolo su come configurare il layout di un AlertDialog con file di stile XML. Il problema principale è che sono necessarie definizioni di stile diverse per parametri di layout diversi. Ecco una piastra di caldaia basata sullo stile AlertDialog di Holo Light Platform versione 19 per un file di stile che dovrebbe coprire un sacco di aspetti del layout standard come dimensioni del testo e colori di sfondo.

<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
potrei chiederti perché entrambi abbiamo bisogno di stile e tema per la personalizzazione di AlertDialog? Molte grazie! @nantoka
brainvision,

2
@brainvision Il mio post sul blog ha i dettagli, ma in breve il layout di un AlertDialog proviene da due classi diverse (Dialog e AlertController) che usano file di parametri di layout diversi.
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();

3
La soluzione più semplice ma veloce!
FonzTech,

4
OK, che ne dici di usare qualche attributo per dichiararlo globalmente in "AppTheme"?
pesce morto

2
Questo mi ha aiutato a cambiare i colori dei pulsanti della finestra di dialogo.
Icarovirtual,

1
Grazie amico, mi hai salvato la settimana !!
Clifton Steenkamp,

31

Stavo lottando con questo - puoi modellare lo sfondo del dialogo usando android:alertDialogStyle="@style/AlertDialog" nel tuo tema, ma ignora tutte le impostazioni di testo che hai. Come ha detto @rflexor sopra, non è possibile eseguire l'SDK prima di Honeycomb (bene è possibile utilizzarlo Reflection).

La mia soluzione, in poche parole, è stata lo stile dello sfondo della finestra di dialogo utilizzando quanto sopra, quindi impostare un titolo personalizzato e una vista del contenuto (utilizzando layout uguali a quelli dell'SDK).

Il mio involucro:

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 (tratto dall'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>

Quindi usa CustomAlertDialogBuilderinvece invece di AlertDialog.Buildercreare i tuoi dialoghi, e chiama setTitlee setMessagecome al solito.


3
come hai effettuato l'accesso a android.R.internal.id.alerttitle?
Gilbert,

2
Non l'ho fatto, ho avuto accesso a R.id.alertTitle
Joseph Earl il

28

È possibile assegnare direttamente un tema quando si avvia Builder:

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

Quindi personalizza il tuo tema nel tuo 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
Perfetto. L'unica cosa che ho usatoTheme.AppCompat.Light.Dialog.Alert
ekashking,

11

Per la finestra di dialogo personalizzata:

basta chiamare super(context,R.style.<dialog style>)invece che super(context)nella finestra di dialogo costruttore

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


Per AlertDialog:

Basta creare alertDialog con questo costruttore:

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

1
Non è necessario estendere Dialog con una nuova classe vuota, poiché esiste già una versione del costruttore che prende lo stile del tema.
FindOut_Quran,

@FindOut_Quran Il punto è mostrare come sovrascrivere lo stile in una classe Dialog personalizzata. È solo un esempio, la tua vera classe Dialog avrà anche qualche altro codice.
Niall,

8

Immagino che non si possa fare. Almeno non con il costruttore. Sto lavorando con 1.6 e l'implementazione in Builder.create () è:

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

che chiama il costruttore "non tematico" di AlertDialog, che assomiglia a questo:

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

C'è un secondo costruttore in AlertDialog per cambiare i temi:

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

che il costruttore non chiama.

Se il Dialog è comunque piuttosto generico, proverei a scrivere una sottoclasse di AlertDialog, chiamando il secondo costruttore e usando quella classe invece del meccanismo Builder.


4

Il modo migliore per farlo utilizza la finestra di dialogo personalizzata e personalizza in base alle tue esigenze qui è l'esempio della finestra di dialogo personalizzata .....

inserisci qui la descrizione dell'immagine

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

}

Ecco il layout 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
Temare e utilizzare una vista personalizzata sono 2 cose diverse e hanno scopi diversi.
jmc34,

3

Chiunque provi a farlo all'interno di un frammento (usando la libreria di supporto cioè pre API 11) dovrebbe andare con questo:

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 mi ha dato la spinta per estendere AlertDialog ed esporre il costruttore grazie


Il costruttore AlertDialog.Builder(Context, int)funziona solo su API 11 e successive. Il codice si arresta in modo anomalo su versioni precedenti di Android.
Joseph Earl

@JosephEarl (utilizzando la libreria di supporto cioè pre API 11)
Blundell

Mio cattivo, usi il costruttore di dialoghi e non il costruttore di dialog dialog.
Joseph Earl,

2

La soluzione di Arve Waltin sembra buona, anche se non l'ho ancora testata. C'è un'altra soluzione nel caso in cui si hanno difficoltà a raggiungere che per lavoro .... Estendere AlertDialog.Buildere sovrascrivere tutti i metodi (ad es. setText, setTitle,setView , Ecc) non è per impostare l'attuale testo / titolo / vista del dialogo, ma di creare una nuova vista all'interno la finestra di dialogo fa tutto lì. Quindi sei libero di modellare tutto come preferisci.

Per chiarire, per quanto riguarda la classe genitore, la vista è impostata e nient'altro.

Per quanto riguarda la tua classe estesa personalizzata, tutto è fatto in quella vista.


0

Non sono sicuro di come funzionerebbe la soluzione di Arve in una finestra di dialogo personalizzata con builder in cui la vista viene gonfiata tramite LayoutInflator.

La soluzione dovrebbe essere quella di inserire il ContextThemeWrapper nel gonfiatore attraverso cloneInContext():

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

-1

Può essere fatto semplicemente usando setView () del Builder. Puoi creare qualsiasi vista a tua scelta e inserirla nel builder. Questo funziona bene. Uso un TextView personalizzato che viene reso dal generatore di dialoghi. Non imposto il messaggio e questo spazio viene utilizzato per rendere la mia visualizzazione di testo personalizzata.


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

Ti dispiace formattare il codice con lo snippet di codice integrato?
Adriano,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.