Cuadros de diálogo

Un diálogo es una ventana pequeña que le indica al usuario que debe tomar una decisión o ingresar información adicional. Un diálogo no ocupa toda la pantalla y, generalmente, se usa para eventos modales que requieren que los usuarios realicen alguna acción para poder continuar.

Diseño de diálogos

Para obtener información acerca de cómo diseñar tus diálogos, incluidas recomendaciones para idiomas, lee la guía de diseño Diálogos.

La clase Dialog es la clase de base para los diálogos, pero debes evitar crear instancias de Dialog directamente. En su lugar, usa una de las siguientes subclases:

AlertDialog
Un diálogo que puede mostrar un título, hasta tres botones, una lista de elementos seleccionables o un diseño personalizado.
DatePickerDialog o TimePickerDialog
Un diálogo con una IU predefinida que le permite al usuario seleccionar una fecha o una hora.

Precaución: Android incluye otra clase de diálogo llamada ProgressDialog que muestra un diálogo con una barra de progreso. Este widget es obsoleto porque impide que los usuarios interactúen con la aplicación mientras se muestra el progreso. Si necesitas indicar la carga o un progreso indeterminado, debes seguir las pautas de diseño para Progreso y actividad y usar unaProgressBar en tu diseño, en lugar de usarProgressDialog.

Estas clases definen el estilo y la estructura de tu diálogo, pero debes utilizar un DialogFragment como contenedor. La clase DialogFragment proporciona todos los controles que necesitas para crear tu diálogo y gestionar su apariencia, en lugar de llamar a los métodos del objeto Dialog.

El uso de DialogFragment para administrar el diálogo garantiza que aborde correctamente eventos de ciclo de vida, por ejemplo, cuando el usuario presiona el botón Atrás o gira la pantalla. La clase DialogFragment también te permite reutilizar la IU del diálogo como componente integrable a una IU más grande, al igual que un Fragment tradicional (por ejemplo, cuando deseas que la IU del diálogo se vea diferente en pantallas grandes y pequeñas).

En las siguientes secciones de esta guía, se describe la manera de usar un DialogFragment junto con un objeto AlertDialog. Si quieres crear un selector de fecha y hora, debes leer la guía Selectores.

Nota: Debido a que la clase DialogFragment se agregó originalmente con Android 3.0 (nivel de API 11), en este documento se describe cómo usar la clase DialogFragment que se proporciona en la biblioteca de compatibilidad. Al agregar esta biblioteca a tu app, puedes usar DialogFragment y una variedad de otras API en dispositivos con Android 1.6 o versiones posteriores. Si la versión mínima que admite tu app corresponde al nivel de API 11 o superior, puedes usar la versión de framework de DialogFragment, pero ten en cuenta que los vínculos que aparecen en este documento son para las API de la biblioteca de compatibilidad. Cuando uses la biblioteca de compatibilidad, asegúrate de importar la clase android.support.v4.app.DialogFragment y no android.app.DialogFragment.

Cómo crear un fragmento de diálogo

Puedes lograr una gran variedad de diseños de diálogo, incluidos diseños personalizados y los que se describen en la guía de diseño Diálogos, si extiendes DialogFragment y creas un AlertDialog en el método de devolución de llamada onCreateDialog().

Por ejemplo, a continuación, hay un AlertDialog básico administrado dentro de un DialogFragment:

Kotlin

class StartGameDialogFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)
            builder.setMessage(R.string.dialog_start_game)
                    .setPositiveButton(R.string.start,
                            DialogInterface.OnClickListener { dialog, id ->
                                // START THE GAME!
                            })
                    .setNegativeButton(R.string.cancel,
                            DialogInterface.OnClickListener { dialog, id ->
                                // User cancelled the dialog
                            })
            // Create the AlertDialog object and return it
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

Java

public class StartGameDialogFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.dialog_start_game)
               .setPositiveButton(R.string.start, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // START THE GAME!
                   }
               })
               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // User cancelled the dialog
                   }
               });
        // Create the AlertDialog object and return it
        return builder.create();
    }
}

Figura 1: Diálogo con un mensaje y dos botones de acción

Ahora, cuando creas una instancia de esta clase y llamas a show() en ese objeto, el diálogo aparece como se muestra en la Figura 1.

En la siguiente sección, se describe más en detalle el uso de las API de AlertDialog.Builder para crear el diálogo.

Según la complejidad del diálogo, puedes implementar una variedad de otros métodos de devolución de llamada en el DialogFragment, incluidos todos los métodos del ciclo de vida de Fragment básicos.

Cómo crear un diálogo de alerta

La clase AlertDialog te permite crear una variedad de diseños de diálogo y generalmente es la única clase de diálogo que necesitarás. Como se muestra en la Figura 2, hay tres regiones en un diálogo de alerta:

Figura 2: El diseño del diálogo

  1. Título

    Es opcional y solo se debe usar cuando el área de contenido está ocupada por un mensaje detallado, una lista o un diseño personalizado. Si necesitas indicar un mensaje o una pregunta simple (como el diálogo de la Figura 1), no necesitas un título.

  2. Área de contenido

    Esto puede mostrar un mensaje, una lista u otro diseño personalizado.

  3. Botones de acción

    No debe haber más de tres botones de acción en un diálogo.

La clase AlertDialog.Builder proporciona API que te permiten crear un AlertDialog con estos tipos de contenido, incluido un diseño personalizado.

Para crear un AlertDialog:

Kotlin

// 1. Instantiate an <code><a href="/reference/android/app/AlertDialog.Builder.html">AlertDialog.Builder</a></code> with its constructor
val builder: AlertDialog.Builder? = activity?.let {
    AlertDialog.Builder(it)
}

// 2. Chain together various setter methods to set the dialog characteristics
builder?.setMessage(R.string.dialog_message)
        .setTitle(R.string.dialog_title)

// 3. Get the <code><a href="/reference/android/app/AlertDialog.html">AlertDialog</a></code> from <code><a href="/reference/android/app/AlertDialog.Builder.html#create()">create()</a></code>
val dialog: AlertDialog? = builder?.create()

Java

// 1. Instantiate an <code><a href="/reference/android/app/AlertDialog.Builder.html">AlertDialog.Builder</a></code> with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage(R.string.dialog_message)
       .setTitle(R.string.dialog_title);

// 3. Get the <code><a href="/reference/android/app/AlertDialog.html">AlertDialog</a></code> from <code><a href="/reference/android/app/AlertDialog.Builder.html#create()">create()</a></code>
AlertDialog dialog = builder.create();

Los siguientes temas muestran cómo definir varios atributos de diálogo usando la clase AlertDialog.Builder.

Cómo agregar botones

Para agregar botones de acción como los de la Figura 2, llama a los métodos setPositiveButton() y setNegativeButton():

Kotlin

val alertDialog: AlertDialog? = activity?.let {
    val builder = AlertDialog.Builder(it)
    builder.apply {
        setPositiveButton(R.string.ok,
                DialogInterface.OnClickListener { dialog, id ->
                    // User clicked OK button
                })
        setNegativeButton(R.string.cancel,
                DialogInterface.OnClickListener { dialog, id ->
                    // User cancelled the dialog
                })
    }
    // Set other dialog properties
    ...

    // Create the AlertDialog
    builder.create()
}

Java

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Add the buttons
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // User clicked OK button
           }
       });
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // User cancelled the dialog
           }
       });
// Set other dialog properties
...

// Create the AlertDialog
AlertDialog dialog = builder.create();

Los métodos set...Button() requieren un título para el botón (proporcionado por un recurso de strings) y un DialogInterface.OnClickListener que defina la acción que se realizará cuando el usuario presione el botón.

Hay tres botones de acción diferentes que puedes agregar:

Positivo
Debes usar este botón para aceptar y continuar con la acción (la acción "Aceptar").
Negativo
Debes usar este botón para cancelar la acción.
Neutro
Debes usar este botón cuando el usuario no quiera continuar con la acción, pero no necesariamente quiera cancelar. Aparece entre los botones positivo y negativo. Por ejemplo, la acción podría ser "Recordarme más tarde".

Puedes agregar un solo tipo de botón a un AlertDialog. Es decir, no puedes tener más de un botón "positivo".

Figura 3: Diálogo con un título y una lista

Agregar una lista

Hay tres tipos de listas disponibles con las API de AlertDialog:

  • Una lista de opción única tradicional
  • Una lista de opción única persistente (botones de selección)
  • Una lista de opciones múltiples persistente (casillas de verificación)

Para crear una lista de opción única como la de la Figura 3, usa el método setItems():

Kotlin

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity?.let {
        val builder = AlertDialog.Builder(it)
        builder.setTitle(R.string.pick_color)
                .setItems(R.array.colors_array,
                        DialogInterface.OnClickListener { dialog, which ->
                            // The 'which' argument contains the index position
                            // of the selected item
                        })
        builder.create()
    } ?: throw IllegalStateException("Activity cannot be null")
}

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle(R.string.pick_color)
           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int which) {
               // The 'which' argument contains the index position
               // of the selected item
           }
    });
    return builder.create();
}

Como la lista aparece en el área de contenido del diálogo, este no puede mostrar un mensaje ni una lista, y debes proporcionar un título para el diálogo con setTitle(). Para especificar los elementos de la lista, llama a setItems() pasando un array. Alternativamente, puedes especificar una lista utilizando setAdapter(). Esto te permite respaldar la lista con datos dinámicos (por ejemplo, los de una base de datos) usando un ListAdapter.

Si decides respaldar tu lista con un ListAdapter, usa siempre un Loader de modo que el contenido se cargue de forma asíncrona. Esto se describe más detalladamente en Cómo crear diseños con un adaptador y en la guía Cargadores.

Nota: De forma predeterminada, cuando tocas un elemento de la lista, se descarta el diálogo, a menos que estés usando una de las siguientes listas de opción persistentes.

Cómo agregar una lista persistente de opción única u opciones múltiples

Para agregar una lista de elementos de varias opciones (casillas de verificación) o de una opción (botones de opción), usa los métodos setMultiChoiceItems() o setSingleChoiceItems(), respectivamente.

Figura 4: Una lista con elementos de opción múltiple

Por ejemplo, aquí te mostramos cómo puedes crear una lista de opción múltiple como la que se muestra en la Figura 4, que guarda los elementos seleccionados en una ArrayList:

Kotlin

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity?.let {
        val selectedItems = ArrayList<Int>() // Where we track the selected items
        val builder = AlertDialog.Builder(it)
        // Set the dialog title
        builder.setTitle(R.string.pick_toppings)
                // Specify the list array, the items to be selected by default (null for none),
                // and the listener through which to receive callbacks when items are selected
                .setMultiChoiceItems(R.array.toppings, null,
                        DialogInterface.OnMultiChoiceClickListener { dialog, which, isChecked ->
                            if (isChecked) {
                                // If the user checked the item, add it to the selected items
                                selectedItems.add(which)
                            } else if (selectedItems.contains(which)) {
                                // Else, if the item is already in the array, remove it
                                selectedItems.remove(which)
                            }
                        })
                // Set the action buttons
                .setPositiveButton(R.string.ok,
                        DialogInterface.OnClickListener { dialog, id ->
                            // User clicked OK, so save the selectedItems results somewhere
                            // or return them to the component that opened the dialog
                            ...
                        })
                .setNegativeButton(R.string.cancel,
                        DialogInterface.OnClickListener { dialog, id ->
                            ...
                        })

        builder.create()
    } ?: throw IllegalStateException("Activity cannot be null")
}

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    selectedItems = new ArrayList();  // Where we track the selected items
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Set the dialog title
    builder.setTitle(R.string.pick_toppings)
    // Specify the list array, the items to be selected by default (null for none),
    // and the listener through which to receive callbacks when items are selected
           .setMultiChoiceItems(R.array.toppings, null,
                      new DialogInterface.OnMultiChoiceClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int which,
                       boolean isChecked) {
                   if (isChecked) {
                       // If the user checked the item, add it to the selected items
                       selectedItems.add(which);
                   } else if (selectedItems.contains(which)) {
                       // Else, if the item is already in the array, remove it
                       selectedItems.remove(which);
                   }
               }
           })
    // Set the action buttons
           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   // User clicked OK, so save the selectedItems results somewhere
                   // or return them to the component that opened the dialog
                   ...
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   ...
               }
           });

    return builder.create();
}

Aunque tanto una lista tradicional como una que tiene botones de selección proporcionan una acción de "opción única", debes utilizar setSingleChoiceItems() si deseas mantener la elección del usuario. Es decir, si, al abrir de nuevo el diálogo más tarde, se indica cuál es la opción actual del usuario, se crea una lista con botones de selección.

Cómo crear un diseño personalizado

Figura 5: Un diseño de diálogo personalizado

Si quieres un diseño personalizado en un diálogo, crea un diseño y agrégalo a un AlertDialog llamando a setView() en tu objeto AlertDialog.Builder.

De forma predeterminada, el diseño personalizado ocupa toda la ventana de diálogo, pero aún puedes usar métodos AlertDialog.Builder para agregar botones y un título.

Por ejemplo, aquí te mostramos un archivo de diseño para el diálogo de la Figura 5:

res/layout/dialog_signin.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageView
        android:src="@drawable/header_logo"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:scaleType="center"
        android:background="#FFFFBB33"
        android:contentDescription="@string/app_name" />
    <EditText
        android:id="@+id/username"
        android:inputType="textEmailAddress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="4dp"
        android:hint="@string/username" />
    <EditText
        android:id="@+id/password"
        android:inputType="textPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="16dp"
        android:fontFamily="sans-serif"
        android:hint="@string/password"/>
</LinearLayout>

Sugerencia: De forma predeterminada, cuando estableces un elemento EditText para que use el tipo de entrada "textPassword", la familia de fuentes se establece en monoespacio, de modo que deberías cambiarla a "sans-serif" para que ambos campos de texto usen un estilo similar.

Para aumentar el diseño de tu DialogFragment, obtén un LayoutInflater con getLayoutInflater() y llama a inflate(), donde el primer parámetro es el ID de los recursos del diseño, y el segundo, una vista superior para el diseño. Luego, puedes llamar a setView() para colocar el diseño en el diálogo.

Kotlin

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity?.let {
        val builder = AlertDialog.Builder(it)
        // Get the layout inflater
        val inflater = requireActivity().layoutInflater;

        // Inflate and set the layout for the dialog
        // Pass null as the parent view because its going in the dialog layout
        builder.setView(inflater.inflate(R.layout.dialog_signin, null))
                // Add action buttons
                .setPositiveButton(R.string.signin,
                        DialogInterface.OnClickListener { dialog, id ->
                            // sign in the user ...
                        })
                .setNegativeButton(R.string.cancel,
                        DialogInterface.OnClickListener { dialog, id ->
                            getDialog().cancel()
                        })
        builder.create()
    } ?: throw IllegalStateException("Activity cannot be null")
}

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Get the layout inflater
    LayoutInflater inflater = requireActivity().getLayoutInflater();

    // Inflate and set the layout for the dialog
    // Pass null as the parent view because its going in the dialog layout
    builder.setView(inflater.inflate(R.layout.dialog_signin, null))
    // Add action buttons
           .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   // sign in the user ...
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   LoginDialogFragment.this.getDialog().cancel();
               }
           });
    return builder.create();
}

Sugerencia: Si quieres un diálogo personalizado, puedes mostrar un Activity como un diálogo en lugar de usar las API Dialog. Simplemente, crea una actividad y establece su tema en Theme.Holo.Dialog en el elemento de manifiesto <activity>:

<activity android:theme="@android:style/Theme.Holo.Dialog" >

Se ve así. Ahora la actividad se muestra en una ventana de diálogo en lugar de mostrarse en pantalla completa.

Cómo pasar eventos de vuelta al host del diálogo

Cuando el usuario toque uno de los botones de acción del diálogo o seleccione un elemento de su lista, tu DialogFragment debería realizar la acción necesaria por sí solo, pero a menudo es posible que quieras enviar el evento a la actividad o al fragmento que abrió el diálogo. Para ello, define una interfaz con un método para cada tipo de evento de clic. A continuación, implementa esa interfaz en el componente de host que recibirá los eventos de acción del cuadro de diálogo.

Por ejemplo, aquí te mostramos un DialogFragment que define una interfaz a través de la cual envía eventos de regreso a la actividad de host:

Kotlin

class NoticeDialogFragment : DialogFragment() {
    // Use this instance of the interface to deliver action events
    internal lateinit var listener: NoticeDialogListener

    /* The activity that creates an instance of this dialog fragment must
     * implement this interface in order to receive event callbacks.
     * Each method passes the DialogFragment in case the host needs to query it. */
    interface NoticeDialogListener {
        fun onDialogPositiveClick(dialog: DialogFragment)
        fun onDialogNegativeClick(dialog: DialogFragment)
    }

    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            listener = context as NoticeDialogListener
        } catch (e: ClassCastException) {
            // The activity doesn't implement the interface, throw exception
            throw ClassCastException((context.toString() +
                    " must implement NoticeDialogListener"))
        }
    }
}

Java

public class NoticeDialogFragment extends DialogFragment {

    /* The activity that creates an instance of this dialog fragment must
     * implement this interface in order to receive event callbacks.
     * Each method passes the DialogFragment in case the host needs to query it. */
    public interface NoticeDialogListener {
        public void onDialogPositiveClick(DialogFragment dialog);
        public void onDialogNegativeClick(DialogFragment dialog);
    }

    // Use this instance of the interface to deliver action events
    NoticeDialogListener listener;

    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            listener = (NoticeDialogListener) context;
        } catch (ClassCastException e) {
            // The activity doesn't implement the interface, throw exception
            throw new ClassCastException(activity.toString()
                    + " must implement NoticeDialogListener");
        }
    }
    ...
}

La actividad que aloja el diálogo crea una instancia del diálogo con el constructor del fragmento de diálogo y recibe los eventos del diálogo a través de una implementación de la interfaz NoticeDialogListener:

Kotlin

class MainActivity : FragmentActivity(),
        NoticeDialogFragment.NoticeDialogListener {

    fun showNoticeDialog() {
        // Create an instance of the dialog fragment and show it
        val dialog = NoticeDialogFragment()
        dialog.show(supportFragmentManager, "NoticeDialogFragment")
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following methods
    // defined by the NoticeDialogFragment.NoticeDialogListener interface
    override fun onDialogPositiveClick(dialog: DialogFragment) {
        // User touched the dialog's positive button
    }

    override fun onDialogNegativeClick(dialog: DialogFragment) {
        // User touched the dialog's negative button
    }
}

Java

public class MainActivity extends FragmentActivity
                          implements NoticeDialogFragment.NoticeDialogListener{
    ...

    public void showNoticeDialog() {
        // Create an instance of the dialog fragment and show it
        DialogFragment dialog = new NoticeDialogFragment();
        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following methods
    // defined by the NoticeDialogFragment.NoticeDialogListener interface
    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        // User touched the dialog's positive button
        ...
    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {
        // User touched the dialog's negative button
        ...
    }
}

Debido a que la actividad de host implementa el NoticeDialogListener (ejecutado por el método de devolución de llamada onAttach() que se mostró anteriormente), el fragmento de diálogo puede usar los métodos de devolución de llamada de la interfaz para enviar eventos de clic a la actividad:

Kotlin

    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        return activity?.let {
            // Build the dialog and set up the button click handlers
            val builder = AlertDialog.Builder(it)

            builder.setMessage(R.string.dialog_start_game)
                    .setPositiveButton(R.string.start,
                            DialogInterface.OnClickListener { dialog, id ->
                                // Send the positive button event back to the host activity
                                listener.onDialogPositiveClick(this)
                            })
                    .setNegativeButton(R.string.cancel,
                            DialogInterface.OnClickListener { dialog, id ->
                                // Send the negative button event back to the host activity
                                listener.onDialogNegativeClick(this)
                            })

            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }

Java

public class NoticeDialogFragment extends DialogFragment {
    ...

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Build the dialog and set up the button click handlers
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.dialog_start_game)
               .setPositiveButton(R.string.start, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the positive button event back to the host activity
                       listener.onDialogPositiveClick(NoticeDialogFragment.this);
                   }
               })
               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the negative button event back to the host activity
                       listener.onDialogNegativeClick(NoticeDialogFragment.this);
                   }
               });
        return builder.create();
    }
}

Cómo exhibir un diálogo

Cuando desees mostrar tu diálogo, crea una instancia de tu DialogFragment, llama a show() y pasa el FragmentManager y un nombre de etiqueta para el fragmento de diálogo.

Puedes obtener el FragmentManager llamando a getSupportFragmentManager() desde la FragmentActivity o getFragmentManager() desde un Fragment. Por ejemplo:

Kotlin

fun confirmStartGame() {
    val newFragment = StartGameDialogFragment()
    newFragment.show(supportFragmentManager, "game")
}

Java

public void confirmStartGame() {
    DialogFragment newFragment = new StartGameDialogFragment();
    newFragment.show(getSupportFragmentManager(), "game");
}

El segundo argumento, "game", es un nombre de etiqueta único que el sistema usa para guardar y restaurar el estado del fragmento cuando es necesario. La etiqueta también te permite obtener un controlador para el fragmento llamando a findFragmentByTag().

Cómo exhibir un diálogo en pantalla completa o como fragmento integrado

Podrías tener un diseño en el que quieras que aparezca una parte de la IU como un diálogo en algunas situaciones, pero como pantalla completa o fragmento integrado en otras (puede depender de si el dispositivo tiene una pantalla grande o pequeña). La clase DialogFragment te ofrece esta flexibilidad porque puede, de todos modos, comportarse como un Fragment integrable.

Sin embargo, en este caso no puedes usar AlertDialog.Builder ni otros objetos Dialog para crear el diálogo. Si deseas que DialogFragment sea integrable, debes definir la IU del diálogo en un diseño y luego cargar el diseño en la devolución de llamada onCreateView().

Este es un DialogFragment de ejemplo que puede aparecer como un diálogo o un fragmento integrable (con un diseño llamado purchase_items.xml):

Kotlin

class CustomDialogFragment : DialogFragment() {

    /** The system calls this to get the DialogFragment's layout, regardless
    of whether it's being displayed as a dialog or an embedded fragment. */
    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
        // Inflate the layout to use as dialog or embedded fragment
        return inflater.inflate(R.layout.purchase_items, container, false)
    }

    /** The system calls this only when creating the layout in a dialog. */
    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        // The only reason you might override this method when using onCreateView() is
        // to modify any dialog characteristics. For example, the dialog includes a
        // title by default, but your custom layout might not need it. So here you can
        // remove the dialog title, but you must call the superclass to get the Dialog.
        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        return dialog
    }
}

Java

public class CustomDialogFragment extends DialogFragment {
    /** The system calls this to get the DialogFragment's layout, regardless
        of whether it's being displayed as a dialog or an embedded fragment. */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout to use as dialog or embedded fragment
        return inflater.inflate(R.layout.purchase_items, container, false);
    }

    /** The system calls this only when creating the layout in a dialog. */
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // The only reason you might override this method when using onCreateView() is
        // to modify any dialog characteristics. For example, the dialog includes a
        // title by default, but your custom layout might not need it. So here you can
        // remove the dialog title, but you must call the superclass to get the Dialog.
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        return dialog;
    }
}

A continuación se muestra parte de un código que decide si mostrar el fragmento como un diálogo o una IU en pantalla completa en función del tamaño de la pantalla:

Kotlin

fun showDialog() {
    val fragmentManager = supportFragmentManager
    val newFragment = CustomDialogFragment()
    if (isLargeLayout) {
        // The device is using a large layout, so show the fragment as a dialog
        newFragment.show(fragmentManager, "dialog")
    } else {
        // The device is smaller, so show the fragment fullscreen
        val transaction = fragmentManager.beginTransaction()
        // For a little polish, specify a transition animation
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        // To make it fullscreen, use the 'content' root view as the container
        // for the fragment, which is always the root view for the activity
        transaction
                .add(android.R.id.content, newFragment)
                .addToBackStack(null)
                .commit()
    }
}

Java

public void showDialog() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    CustomDialogFragment newFragment = new CustomDialogFragment();

    if (isLargeLayout) {
        // The device is using a large layout, so show the fragment as a dialog
        newFragment.show(fragmentManager, "dialog");
    } else {
        // The device is smaller, so show the fragment fullscreen
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        // For a little polish, specify a transition animation
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        // To make it fullscreen, use the 'content' root view as the container
        // for the fragment, which is always the root view for the activity
        transaction.add(android.R.id.content, newFragment)
                   .addToBackStack(null).commit();
    }
}

Para obtener más información acerca de cómo realizar transacciones con fragmentos, lee la guía Fragmentos.

En este ejemplo, el valor booleano mIsLargeLayout especifica si el dispositivo actual debe usar el diseño grande de la app (y mostrar ese fragmento como un diálogo en lugar de pantalla completa). La mejor manera de establecer este valor booleano es declarar un valor de recurso booleano con un valor de recurso alternativo para diferentes tamaños de pantalla. Por ejemplo, a continuación se muestran dos versiones del recurso booleano para diferentes tamaños de pantalla:

res/values/bools.xml

<!-- Default boolean values -->
<resources>
    <bool name="large_layout">false</bool>
</resources>

res/values-large/bools.xml

<!-- Large screen boolean values -->
<resources>
    <bool name="large_layout">true</bool>
</resources>

Luego, puedes inicializar el valor mIsLargeLayout durante el método onCreate() de la actividad:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    isLargeLayout = resources.getBoolean(R.bool.large_layout)
}

Java

boolean isLargeLayout;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    isLargeLayout = getResources().getBoolean(R.bool.large_layout);
}

Cómo exhibir una actividad como un diálogo en pantallas grandes

En lugar de mostrar un diálogo como una IU de pantalla completa en pantallas pequeñas, puedes lograr el mismo resultado mostrando una Activity como un diálogo en pantallas grandes. El enfoque que elijas dependerá del diseño de tu app, pero mostrar una actividad como diálogo generalmente es útil cuando la app ya está diseñada para pantallas pequeñas y quieres mejorar la experiencia en tablets mostrando una actividad breve como un diálogo.

Para mostrar una actividad como diálogo solo en pantallas grandes, aplica el tema Theme.Holo.DialogWhenLarge al elemento de manifiesto <activity>:

<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >

Si deseas obtener más información para diseñar tus actividades con temas, lee la guía Estilos y temas.

Cómo descartar un diálogo

Cuando el usuario toca cualquiera de los botones de acción creados con un AlertDialog.Builder, el sistema descarta el diálogo por ti.

El sistema también descarta el diálogo cuando el usuario toca un elemento en una lista de diálogo, excepto cuando la lista usa botones de selección o casillas de verificación. De lo contrario, puedes descartar el diálogo manualmente llamando a dismiss() en tu DialogFragment.

En caso de que necesites realizar determinadas acciones cuando el diálogo desaparezca, puedes implementar el método onDismiss() en tu DialogFragment.

También puedes cancelar un diálogo. Este es un evento especial que indica que el usuario explícitamente abandonó el diálogo sin completar la tarea. Esto ocurre si el usuario presiona el botón Atrás, toca la pantalla fuera del área de diálogo o si llamas explícitamente a cancel() en Dialog (por ejemplo, en respuesta a un botón "Cancelar" en el diálogo).

Como se muestra en el ejemplo anterior, puedes responder al evento de cancelación implementando onCancel() en tu clase DialogFragment.

Nota: El sistema llama a onDismiss() con cada evento que invoca la devolución de llamada onCancel(). Sin embargo, si llamas a Dialog.dismiss() o a DialogFragment.dismiss(), el sistema llama a onDismiss(), pero no a onCancel(). Por lo tanto, generalmente, debes llamar a dismiss() cuando el usuario presiona el botón positivo en tu diálogo para quitar el diálogo de la vista.