Diseño Android: Cuadros de diálogo de selección

Última actualización: 13/12/2020

android

Los cuadros de diálogo son un elemento básico de la mayoría de interfaces de usuario y no necesitan presentación alguna. Según las guías de estilos de Material Design, «informan a los usuarios sobre una tarea específica y pueden contener información crítica, requerir decisiones o implicar varias tareas.» En Android, son ventanas que se muestran sobre una pantalla, representada por una Activity o un Fragment, y que bloquean el uso de la pantalla subyacente. Esta ventana es gestionada directamente por una implementación del contrato android.content.DialogInterface, aunque en la práctica será suficiente con utilizar alguna de las implementaciones que ya incluye Android.

El siguiente diagrama muestra las clases e interfaces más importantes para los cuadros de diálogos proporcionadas por Android de forma nativa.

Aunque no es necesario, la práctica habitual y recomendada desde Google, es encapsular los cuadros de diálogo en fragments que hereden de DialogFragment disponible en AndroidX, la evolución de la ya obsoleta biblioteca de compatibilidad. Esto nos permitirá tener un aspecto consistente en todas las versiones de Android así como poder disfrutar de las mejoras y correcciones de errores que se vayan realizando.

Cursos aplicaciones móviles

En este tutorial vamos a crear cuadros de diálogo encapsulados en fragments para seleccionar uno o varios elementos de un listado utilizando los recursos ya proporcionados por Android. Este es el ejemplo que vamos a desarrollar:

Proyecto de ejemplo

El proyecto de ejemplo de este tutorial será compatible con Android 4.4 (Api 16) y superior. Para estar a la última usaremos Material Components for Android.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "com.danielme.android.dialogfragmentpicker"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
}

Aplicamos un tema de Material Components y definimos el estilo de la ActionBar-Toolbar (para más información ver este tutorial).

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorOnPrimary">@android:color/white</item>
        <item name="colorPrimaryDark">@color/primaryDark</item>
        <item name="colorSecondary">@color/colorSecondary</item>
    </style>

    <style name="AppTheme.Toolbar" parent="@style/Widget.MaterialComponents.Toolbar.PrimarySurface">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">?attr/actionBarSize</item>
    </style>

</resources>

El AlertDialog de Android

En primer lugar, vamos a echar un vistazo muy rápido a los elementos gráficos más importantes que pueden formar parte del componente Alert Dialog de Android.

Este Alert Dialog se define utilizando un builder, aunque en el ejemplo usaremos la subclase MaterialAlertDialogBuilder para que se apliquen correctamente los estilos de Material Components.

 MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext());
        builder.setTitle("title")              
                .setMessage("message")
                .setNegativeButton("negative", null)
                .setNeutralButton("neutral", null)
                .setPositiveButton("positive", null);

builder.create().show()

A tener en cuenta:

  • Si un elemento no se define con el seter no se muestra.

  • Al pulsarse un botón el cuadro de diálogo se cierra siempre. Si a ese botón le hemos asignado un listener, se ejecutará antes de cerrarse.
  • El cuadro de diálogo se cierra al pulsarse el botón «back» de Android o fuera del cuadro de diálogo. Este comportamiento se puede configurar con el método setCancelable. Pero si el Alert Dialog está encapsulado en un DialogFragment, el método a llamar es el setCancelable del DialogFragment.
  • Si el Alert Dialog se muestra directamente desde una Activity, si esta se destruye y el AlertDialog se está mostrando se producirá un memory leak por lo que deberemos cerrar el diálogo antes invocando a dismiss.

Diálogo de selección simple

Tal y como se ha comentado en la introducción, nuestro cuadro de diálogo estará encapsulado dentro de un fragment. Para ello vamos a recurrir a la clase AppCompatDialogFragment de AndroidX.

En nuestro fragment, sobrescribimos el método onCreateDialog el cual devolverá el Dialog que mostrará el Fragment. Este dialog lo creamos de forma estándar, esto es, utilizando el builder que vimos un poco más arriba. Para el caso concreto del diálogo de selección, tenemos que utilizar una de las sobrecargas del método setSingleChoiceItems.

En nuestro ejemplo, vamos a utilizar la versión de este método que recibe un array con los textos de cada opción que puede ser seleccionada, el índice en ese array del elemento preseleccionado si lo hubiera, y el listener que atiende la selección de uno de los items y que usaremos para guardar en un atributo de la clase el índice del elemento seleccionado. El resto de elementos del diálogo (título y botones) los vamos a configurar como en cualquier Alert Dialog.

Una primera versión del fragment es la que sigue.

package com.danielme.android.dialogfragmentpicker;

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

import androidx.appcompat.app.AppCompatDialogFragment;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

import android.widget.Toast;

public class DialogSinglePickerFragment extends AppCompatDialogFragment {

    private static final int UNSELECTED = -1;
    private int selected;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final String[] brands = {getString(R.string.htc), getString(R.string.lg), getString(R.string.meizu),
                getString(R.string.motorola), getString(R.string.samsung)};

       return new MaterialAlertDialogBuilder(getContext())
                .setTitle(R.string.pick_brand)
                .setSingleChoiceItems(brands, UNSELECTED, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        selected = which;
                    }
                })
                .setNegativeButton(android.R.string.cancel, null)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (selected != UNSELECTED) {
                            Toast.makeText(getContext(), brands[selected], Toast.LENGTH_SHORT).show();
                        }
                    }
                })
             .create();
    }

}

Ahora vamos a añadir algunas mejoras:

  • Indicar al Fragment el elemento preseleccionado (opcional). Para ello vamos a recurrir al clásico patrón «constructor estático» debido a que los fragments siempre tienen que ser instanciados con el constructor vacío.
  • El fragment se muestra en una Activity lo que implica que al ser rotada perderemos el valor almacenado en el atributo selected. Evitaremos esto implementando el método onSaveInstanceState y recuperando el valor guardado en el onCreateDialog.
  • Para hacer el Fragment más flexible y genérico, también vamos a pasar como parámetros la lista de items y el título.

El código completo del fragment queda como sigue.

package com.danielme.android.dialogfragmentpicker;

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

import androidx.appcompat.app.AppCompatDialogFragment;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

import android.widget.Toast;

public class DialogSinglePickerFragment extends AppCompatDialogFragment {

    private static final int UNSELECTED = -1;
    private static final String ARG_SELECTED = "ARG_SELECTED";
    private static final String ARG_ITEMS = "ARG_ITEMS";
    private static final String ARG_TITLE = "ARG_TITLE";
    private static final String STATE_SELECTED = "STATE_SELECTED";

    private int selected;

    public static DialogSinglePickerFragment newInstance(Integer selection, String[] items, String title) {
        DialogSinglePickerFragment fragment = new DialogSinglePickerFragment();
        Bundle args = new Bundle();
        if (selection != null) {
            args.putInt(ARG_SELECTED, selection);
        }
        args.putStringArray(ARG_ITEMS, items);
        args.putString(ARG_TITLE, title);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        if (savedInstanceState != null) { //rotation
            selected = savedInstanceState.getInt(STATE_SELECTED, UNSELECTED);
        } else if (getArguments() != null) {
            selected = getArguments().getInt(ARG_SELECTED, UNSELECTED);
        }

        final String[] brands = getArguments().getStringArray(ARG_ITEMS);

        return new MaterialAlertDialogBuilder(getContext())
                .setTitle(getArguments().getString(ARG_TITLE))
                .setSingleChoiceItems(brands, selected, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        selected = which;
                    }
                })
                .setNegativeButton(android.R.string.cancel, null)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (selected != UNSELECTED) {
                            Toast.makeText(getContext(), brands[selected], Toast.LENGTH_SHORT).show();
                        }
                    }
                }).
         create();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_SELECTED, selected);
    }

}

El fragment se muestra desde la Activity con un botón.

 findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DialogSinglePickerFragment dialogFragment = DialogSinglePickerFragment.newInstance(4, brands, getString(R.string.pick_brand));
                dialogFragment.show(getSupportFragmentManager(), DialogSinglePickerFragment.class.getSimpleName());
            }
        });

Diálogo de selección múltiple

Este fragment es muy parecido al diálogo de selección de un único elemento, tan sólo hay dos diferencias significativas:

  • Ahora usaremos el método setMultiChoiceItems en lugar de setSingleChoiceItems.
  • Para almacenar las posiciones de los items seleccionados necesitamos un array de boolean del mismo tamaño que el array de items. Este array, que en el código he denominado selected, indicará para cada índice de los items seleccionables si el item está seleccionado (true) o no (false).

    Teniendo en cuenta estas diferencias, el nuevo fragment queda como sigue.

    package com.danielme.android.dialogfragmentpicker;
    
    import android.app.Dialog;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import androidx.appcompat.app.AppCompatDialogFragment;
    
    import com.google.android.material.dialog.MaterialAlertDialogBuilder;
    
    import android.widget.Toast;
    
    public class DialogMultiplePickerFragment extends AppCompatDialogFragment {
    
        public static final String SELECTION = "SELECTION";
    
        private static final String ARG_SELECTED = "ARG_SELECTED";
        private static final String STATE_SELECTED = "STATE_SELECTED";
        private static final String ARG_ITEMS = "ARG_ITEMS";
        private static final String ARG_TITLE = "ARG_TITLE";
    
        private boolean[] selected;
    
        public static DialogMultiplePickerFragment newInstance(String[] items, String title, int... selection) {
            DialogMultiplePickerFragment fragment = new DialogMultiplePickerFragment();
            Bundle args = new Bundle();
            if (selection != null) {
                args.putIntArray(ARG_SELECTED, selection);
            }
            args.putStringArray(ARG_ITEMS, items);
            args.putString(ARG_TITLE, title);
            fragment.setArguments(args);
            return fragment;
        }
    
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final CharSequence[] brands = getArguments().getStringArray(ARG_ITEMS);
    
            if (savedInstanceState != null) { //rotation
                selected = savedInstanceState.getBooleanArray(STATE_SELECTED);
            } else if (getArguments() != null) {
                selected = new boolean[brands.length];
                int[] selection = getArguments().getIntArray(ARG_SELECTED);
                for (int aSelection : selection) {
                    selected[aSelection] = true;
                }
            }
    
            return new MaterialAlertDialogBuilder(getContext())
                   .setTitle(getArguments().getString(ARG_TITLE)).setMultiChoiceItems(brands, selected,
                    new DialogInterface.OnMultiChoiceClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                            selected[which] = isChecked;
                        }
                    })
                    .setNegativeButton(android.R.string.cancel, null)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            StringBuilder sb = new StringBuilder();
                            for (int i = 0; i < selected.length; i++) {
                                if (selected[i]) {
                                    sb.append(brands[i]).append(" ");
                                }
                            }
    
                            Toast.makeText(getContext(), sb.toString(), Toast.LENGTH_SHORT).show();
    
                        }
    
                    })
                  .create();
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putBooleanArray(STATE_SELECTED, selected);
        }
    
    }
    

    Desde la Activity vamos mostrar el diálogo del siguiente modo, con los elementos 0 y 3 seleccionados

    findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    DialogMultiplePickerFragment dialogFragment = DialogMultiplePickerFragment.newInstance(brands, getString(R.string.pick_brands), 0, 3);
                    dialogFragment.show(getSupportFragmentManager(), DialogMultiplePickerFragment.class.getSimpleName());
                }
            });
    

    Retorno de parámetros

    Cuando el usuario selecciona algún elemento y pulsa Ok, debemos devolver a la Activity los elementos seleccionados. Este comportamiento puede implementarse siguiendo las dos estrategias que se explican a continuación.

    Llamar a la Activity o al Fragment

    Podemos hacer que el DialogFragment invoque un método de la Activity o el Fragment que lo está mostrando. Para desacoplar el DialogFragment de la Activity, definiremos una interfaz y haremos que sea implementada por la Activity o Fragment.

    
    package com.danielme.android.dialogfragmentpicker;
    
    public interface DialogPickerFragmentListener {
    
        void getSelected(String selected);
    }
    

    Vamos a aplicar esta estrategia, explicada con un ejemplo en la documentación oficial de Android, a nuestro DialogSinglePickerFragment. Eso sí, la documentación no parece estar actualizada en estos momentos, y en lugar del método onAttach(Activity activity) que está deprecated, utilizaré onAttach(Context context). En este último método recibimos la Activity que está mostrando el DialogFragment, y guardamos su referencia para poder llamar al método getSelected al pulsarse el botón OK del diálogo. De este modo tendremos en la Activity la opción seleccionada.

    package com.danielme.android.dialogfragmentpicker;
    
    import android.app.Dialog;
    import android.content.Context;
    import android.os.Bundle;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatDialogFragment;
    
    import com.google.android.material.dialog.MaterialAlertDialogBuilder;
    
    public class DialogSinglePickerFragment extends AppCompatDialogFragment {
    
      private static final int UNSELECTED = -1;
      private static final String ARG_SELECTED = "ARG_SELECTED";
      private static final String ARG_ITEMS = "ARG_ITEMS";
      private static final String ARG_TITLE = "ARG_TITLE";
      private static final String STATE_SELECTED = "STATE_SELECTED";
    
      private DialogPickerFragmentListener listener;
    
      private int selected;
    
      public static DialogSinglePickerFragment newInstance(Integer selection, String[] items, String title) {
        DialogSinglePickerFragment fragment = new DialogSinglePickerFragment();
        Bundle args = new Bundle();
        if (selection != null) {
          args.putInt(ARG_SELECTED, selection);
        }
        args.putStringArray(ARG_ITEMS, items);
        args.putString(ARG_TITLE, title);
        fragment.setArguments(args);
        return fragment;
      }
    
      // Override the Fragment.onAttach() method to instantiate the DialogListener
      @Override
      public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        // Verify that the host activity implements the callback interface
        try {
          // Instantiate the DialogListener so we can send events to the host
          listener = (DialogPickerFragmentListener) context;
        } catch (ClassCastException e) {
          // The activity doesn't implement the interface, throw exception
          throw new ClassCastException(context.toString()
                  + " must implement DialogSinglePickerFragment");
        }
      }
    
      @NonNull
      @Override
      public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState != null) { //rotation
          selected = savedInstanceState.getInt(STATE_SELECTED, UNSELECTED);
        } else if (getArguments() != null) {
          selected = getArguments().getInt(ARG_SELECTED, UNSELECTED);
        }
    
        final String[] brands = getArguments().getStringArray(ARG_ITEMS);
    
        return new MaterialAlertDialogBuilder(getContext())
                .setTitle(getArguments().getString(ARG_TITLE))
                .setSingleChoiceItems(brands, selected, (dialog, which) -> selected = which)
                .setNegativeButton(android.R.string.cancel, null)
                .setPositiveButton(android.R.string.ok, (dialog, which) -> {
                  if (selected != UNSELECTED) {
                    listener.getSelected(brands[selected]);
                    //Toast.makeText(getContext(), brands[selected], Toast.LENGTH_SHORT).show();
                  }
                })
                .create();
      }
    
      @Override
      public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_SELECTED, selected);
      }
    
    }
    

    En la Activity implementamos esta interfaz, y mostramos el resultado recibido en un TextView.

        @Override
        public void getSelected(String selected) {
            textView.setText(selected);
        }
    

    Si el DialogFragment se muestra desde otro Fragment en lugar de una Activity, no necesitamos sobrescribir el método onAttach. En su lugar, al crear el DialogFragment le pasamos la instancia del Fragment que lo crea con el método setTargetFragment de este modo

     DialogSinglePickerFragment dialogFragment = DialogSinglePickerFragment.newInstance(4, brands, getString(R.string.pick_brand));
     dialogFragment.setTargetFragment(this, 0);
     dialogFragment.show(getSupportFragmentManager(), DialogSinglePickerFragment.class.getSimpleName());
    

    En el DialogFragment, recuperamos el fragment «padre» para pasarle los valores seleccionados:

    ((DialogPickerFragmentListener) getTargetFragment()).getSelected(brands[selected]);
    
    Lanzar un evento

    Una alternativa que permite desacoplar totalmente el DialogFragment de la Activity o Fragment que la contiene es enviar un evento dentro de nuestra aplicación al realizarse la selección. Esta estrategia tiene una ventaja añadida: el evento puede ser atendido por cualquier Activity o Fragment de la aplicación.

    Podemos utilizar el mecanismo de broadcasts locales proporcionado de forma nativa por Android, y que explico en el tutorial Android: mensajes y eventos con Broadcasts, o bien un bus de eventos como EventBus que es lo que suelo hacer en mis proyectos. En este caso, y para mantener el tutorial lo más simple posible, voy a utilizar un broadcast local en el DialogFragment de selección múltiple y para cualquier duda al respecto remito al lector a mencionado tutorial.

    En el Fragment, enviamos el broadcast incluyendo en el Intent la selección.

           return new MaterialAlertDialogBuilder(getContext()).setTitle(getArguments().getString(ARG_TITLE)).setMultiChoiceItems(brands, selected,
                    (dialog, which, isChecked) -> selected[which] = isChecked)
                    .setNegativeButton(android.R.string.cancel, null)
                    .setPositiveButton(android.R.string.ok, (dialog, which) -> {
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < selected.length; i++) {
                            if (selected[i]) {
                                sb.append(brands[i]).append(" ");
                            }
                        }
    
                        //Toast.makeText(getContext(), sb.toString(), Toast.LENGTH_SHORT).show();
                        Intent intent = new Intent();
                        intent.setAction(BROADCAST_MULTIPICK);
                        intent.putExtra(SELECTION, sb.toString());
                        LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
                    }).create();
        }
    

    En la Activity, creamos una clase de tipo BroadcastReceiver y registramos una instancia para que se ejecute cuando el DialogFragment envíe el broadcast. También debemos asegurarnos que el broadcast quede «desregistrado» al destruirse la Activity.

    package com.danielme.android.dialogfragmentpicker;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.localbroadcastmanager.content.LocalBroadcastManager;
    
    public class MainActivity extends AppCompatActivity implements DialogPickerFragmentListener {
    
        private TextView textView;
        private MultiPickBroadcastReceiver receiver;
        private String[] brands;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            setSupportActionBar(findViewById(R.id.toolbar));
    
            textView = findViewById(R.id.textView);
    
            brands = new String[]{getString(R.string.htc), getString(R.string.lg), getString(R.string.meizu),
                    getString(R.string.motorola), getString(R.string.samsung)};
    
            setupButtons();
    
            setupBroadcast();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
        }
    
        private void setupBroadcast() {
            receiver = new MultiPickBroadcastReceiver();
            IntentFilter filter = new IntentFilter();
            filter.addAction(DialogMultiplePickerFragment.BROADCAST_MULTIPICK);
            LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
        }
    
        private void setupButtons() {
            findViewById(R.id.button1).setOnClickListener(v -> {
                DialogSinglePickerFragment dialogFragment =
                        DialogSinglePickerFragment.newInstance(4, brands, getString(R.string.pick_brand));
                dialogFragment.show(getSupportFragmentManager(), DialogSinglePickerFragment.class.getSimpleName());
            });
    
            findViewById(R.id.button2).setOnClickListener(v -> {
                DialogMultiplePickerFragment dialogFragment =
                        DialogMultiplePickerFragment.newInstance(brands, getString(R.string.pick_brands), 0, 3);
                dialogFragment.show(getSupportFragmentManager(), DialogMultiplePickerFragment.class.getSimpleName());
            });
        }
    
        @Override
        public void getSelected(String selected) {
            textView.setText(selected);
        }
    
        class MultiPickBroadcastReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                textView.setText(intent.getStringExtra(DialogMultiplePickerFragment.SELECTION));
            }
        }
    }
    

    Estilos

    En nuestros diálogos de selección no hay mucho que configurar en lo que a estilos respecta pues el estilo que ya tenemos por defecto suele resultar más que suficiente. A los radio\checkbox se les aplica el colorSecondary del tema, que hemos personalizado con un color rojo que sustituye al verde que tiene por defecto, y a los botones colorPrimary. El fondo del cuadro de diálogo es de color colorSurface y los textos colorOnSurface. El diseño es consistente tanto para tema claro como para tema oscuro; para más información consultar Diseño Android: Tema claro y oscuro con Material Components.

    android dialog chooser light and dark

    Podemos personalizar el esquema de colores específicamente para todos los alert dialog de la app y respetando los colores elegidos para el tema principal asignando un estilo personalizado con la propiedad materialAlertDialogTheme.

        <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
            <item name="colorPrimary">@color/primary</item>
            <item name="colorOnPrimary">@android:color/white</item>
            <item name="colorPrimaryDark">@color/primaryDark</item>
            <item name="colorSecondary">@color/colorSecondary</item>
            <item name="materialAlertDialogTheme">@style/ThemeOverlay.App.MaterialAlertDialog</item>
        </style>
    
        <style name="ThemeOverlay.App.MaterialAlertDialog" parent="ThemeOverlay.MaterialComponents.MaterialAlertDialog">
            <item name="colorPrimary">@color/colorButton</item>
            <item name="colorSecondary">@color/colorChecked</item>
        </style>
    

    La aplicación de un tema de forma específica sólo para un cuadro de diálogo en concreto se realiza en el constructor del builder.

    new MaterialAlertDialogBuilder(getContext(), R.style.ThemeOverlay_App_MaterialAlertDialog)
    

    android dialog chooser custom style

    Código de ejemplo

    El proyecto de ejemplo para Android Studio se encuentra disponible en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.