Como alterar o tema para AlertDialog

242

Eu queria saber se alguém poderia me ajudar. Estou tentando criar um AlertDialog personalizado. Para fazer isso, adicionei a seguinte linha de código no 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 está localizado na pasta drawable. Isso também está disponível na pasta res do SDK do Android.

A seguir, a atividade 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 o tema a um AlertDialog, eu tive que definir o tema para o contexto atual.

No entanto, não consigo exibir o aplicativo AlertDialog personalizado. Alguém pode me ajudar com isso?

Min Soo Kim
fonte
Achei este repositório no github muito útil: github.com/StylingAndroid/AlertDialog
esilver

Respostas:

363

No Dialog.java (Android src), um ContextThemeWrapper é usado. Então você pode copiar a ideia e fazer algo como:

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

E então estilize como quiser:

<?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
fonte
62
Não use @android: style / AlertDialog. Não está na API pública. Como consequência, no Android 2.3.3, ele falha ao criar o construtor.
Catalin Morosan 14/03
18
@kaciula É @android:style/Theme.Dialogpúblico? Pode ser usado em seu lugar?
HRJ
24
Sim. É público. Confira developer.android.com/reference/android/R.style.html para obter uma lista de todos os estilos públicos. Lembre-se de que a nomenclatura na API é diferente daquela usada no código. Há um '_' em vez de "." (Theme_Dialog)
Catalin Morosan
2
Onde devo colocar o arquivo xml acima?
Chaitanya Chandurkar
3
Para um tema mais recente que faça parte dos temas de compatibilidade, sugiro usar o Theme.AppCompat.Light.Dialog.Alertestilo como pai do seu estilo personalizado. Mas, se você fizer isso, verifique se está importando import android.support.v7.app.AlertDialog; e nãoimport android.app.AlertDialog
w3bshark 28/03
93

Eu estava tendo esse AlertDialogproblema relacionado ao tema usando o sdk 1.6, conforme descrito aqui: http://markmail.org/message/mj5ut56irkrkc4nr

Resolvi o problema fazendo o seguinte:

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

Espero que isto ajude.

chee
fonte
2
Existem vários temas relevantes; no meu caso, android.R.style.Theme_Holo_Dialog foi um ajuste melhor. Ótima dica.
Johnny O
78

Eu escrevi um artigo no meu blog sobre como configurar o layout de um AlertDialog com arquivos de estilo XML. O principal problema é que você precisa de diferentes definições de estilo para diferentes parâmetros de layout. Aqui está um boilerplate baseado no estilo AlertDialog da Holo Light Platform versão 19 para um arquivo de estilo que deve abranger vários aspectos de layout padrão, como tamanhos de texto e cores de fundo.

<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
fonte
2
posso perguntar por que precisamos de estilo e tema para a personalização do AlertDialog? Muito obrigado! @nantoka
brainvision
2
@brainvision Minha entrada no blog tem os detalhes, mas, em poucas palavras, o layout de um AlertDialog vem de duas classes diferentes (Dialog e AlertController) que usam arquivos de parâmetros de layout diferentes.
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
fonte
3
Solução mais simplista, mas rápida!
FonzTech 17/08/19
4
OK, que tal usar algum atributo para declará-lo globalmente em "AppTheme"?
deadfish
2
Isso me ajudou a alterar as cores dos botões da caixa de diálogo.
icarovirtual 26/03/19
1
Obrigado meu cara, você salvou minha semana !!
Clifton Steenkamp 28/01
31

Eu estava lutando com isso - você pode estilizar o plano de fundo da caixa de diálogo usando o android:alertDialogStyle="@style/AlertDialog"seu tema, mas ignora as configurações de texto que você possui. Como o @rflexor disse acima, isso não pode ser feito com o SDK antes do Honeycomb (bem, você pode usarReflection ).

Minha solução, em poucas palavras, foi estilizar o plano de fundo da caixa de diálogo usando o descrito acima e, em seguida, definir um título e uma exibição de conteúdo personalizados (usando layouts iguais aos do SDK).

Meu invólucro:

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 (extraído do 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>

Em seguida, basta usar em CustomAlertDialogBuildervez de AlertDialog.Buildercriar suas caixas de diálogo e apenas ligar setTitlee setMessagecomo de costume.

Joseph Earl
fonte
3
como você acessou android.R.internal.id.alerttitle?
Gilbert
2
Eu não, eu acessada R.id.alertTitle
Joseph Earl
28

Você pode atribuir diretamente um tema ao iniciar o Builder:

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

Em seguida, personalize seu tema em seu 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
fonte
1
Perfeito. A única coisa que useiTheme.AppCompat.Light.Dialog.Alert
ekashking
11

Para caixa de diálogo personalizada:

basta chamar em super(context,R.style.<dialog style>)vez de super(context)no construtor de diálogo

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


Para AlertDialog:

Basta criar alertDialog com este construtor:

 new AlertDialog.Builder(
 new ContextThemeWrapper(context, android.R.style.Theme_Dialog))
Amir Hossein Ghasemi
fonte
1
Não é necessário estender o Dialog com uma nova classe vazia, pois já existe uma versão do construtor que assume o estilo do tema.
FindOut_Quran
@FindOut_Quran O objetivo é mostrar como substituir o estilo em uma classe Dialog personalizada. É apenas um exemplo, sua classe Dialog real também terá algum outro código.
Niall
8

Eu acho que não pode ser feito. Pelo menos não com o Builder. Estou trabalhando com o 1.6 e a implementação no Builder.create () é:

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

que chama o construtor "não sensível ao tema" do AlertDialog, que se parece com isso:

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

Há um segundo construtor no AlertDialog para alterar os temas:

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

que o construtor simplesmente não chama.

Se o Dialog for bastante genérico, tente escrever uma subclasse de AlertDialog, chamando o segundo construtor e use essa classe em vez do mecanismo Builder.

rflexor
fonte
4

A melhor maneira de fazer isso é usar o diálogo personalizado e personalizar de acordo com as suas necessidades aqui é um exemplo de diálogo personalizado .....

insira a descrição da imagem aqui

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

}

Aqui está o 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>


fonte
7
Temar e usar uma visualização personalizada são duas coisas diferentes e têm finalidades diferentes.
jmc34
3

Qualquer pessoa que tente fazer isso dentro de um fragmento (usando a biblioteca de suporte, ou seja, antes da API 11) deve fazer o seguinte:

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

O @Rflexor me deu uma cutucada para estender o AlertDialog e expor o construtor, graças

Blundell
fonte
O construtor AlertDialog.Builder(Context, int)funciona apenas na API 11 e acima. Seu código falhará nas versões anteriores do Android.
Joseph Earl
@JosephEarl (usando a biblioteca de suporte ou seja, pré API 11)
Blundell
Meu mal, você usa o construtor de diálogo e não o construtor de construtor de diálogo.
Joseph Earl
2

A solução da Arve Waltin parece boa, embora ainda não a tenha testado. Não há outra solução no caso de você ter problemas para conseguir que o trabalho .... Estender AlertDialog.Buildere substituir todos os métodos (por exemplo. setText, setTitle,setView , Etc) não para definir o real texto / título / vista do diálogo, mas para criar uma nova visão dentro a visão do diálogo faz tudo lá. Então você é livre para estilizar tudo como quiser.

Para esclarecer, no que diz respeito à classe pai, a Visualização está definida e nada mais.

No que diz respeito à sua classe estendida personalizada, tudo é feito nessa visualização.

Steven L
fonte
0

Não tenho certeza de como a solução da Arve funcionaria em um diálogo personalizado com o construtor, onde a exibição é inflada por meio de um LayoutInflator.

A solução deve ser inserir o ContextThemeWrapper no inflator por meio de cloneInContext():

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

Isso pode ser feito simplesmente usando o setView () do Builder. Você pode criar qualquer visualização de sua escolha e alimentar o construtor. Isso funciona bem. Eu uso um TextView personalizado que é renderizado pelo construtor de diálogo. Não defino a mensagem e esse espaço é utilizado para renderizar minha visualização de texto personalizada.

AKh
fonte
-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
fonte
Você se importa de formatar seu código com o snippet de código interno?
Adriano