Caixas de diálogo

As caixas de diálogo são pequenas janelas que levam o usuário a tomar uma decisão ou inserir informações adicionais. Elas não ocupam toda a tela e são normalmente usadas para eventos modais que exijam que usuários realizem uma ação antes de continuar.

Design de caixas de diálogo

Para ver mais informações sobre como projetar caixas de diálogo, inclusive recomendações para o idioma, leia o guia de design de Caixas de diálogo.

A classe Dialog é a classe de base para caixas de diálogo, mas você deve evitar instanciar Dialog diretamente. Em vez disso, use uma das subclasses a seguir:

AlertDialog
Uma caixa de diálogo pode exibir um título, até três botões, uma lista de itens selecionáveis ou um layout personalizado.
DatePickerDialog ou TimePickerDialog
Uma caixa de diálogo com uma IU pré definida que permite ao usuário selecionar uma data ou hora.

Cuidado: o Android inclui outra classe de caixa de diálogo chamada ProgressDialog, que exibe uma caixa de diálogo com uma barra de progresso. Esse widget está obsoleto porque impede que os usuários interajam com o aplicativo enquanto o progresso está sendo exibido. Se for necessário indicar o carregamento ou o progresso indeterminado, siga as diretrizes de design paraProgresso e atividade e use umProgressBar no seu layout, em vez de ProgressDialog.

Essas classes definem o estilo e a estrutura da sua caixa de diálogo, mas você deve usar um DialogFragment como um contêiner para sua caixa de diálogo. A classe DialogFragment fornece todos os controles necessários para criar sua caixa de diálogo e gerenciar sua aparência, em vez de chamar métodos no objeto Dialog.

O uso de DialogFragment para gerenciar a caixa de diálogo garante que ela processe corretamente os eventos de ciclos de vida, como quando o usuário pressiona o botão Voltar ou gira a tela. A classe DialogFragment também permite a reutilização da IU da caixa de diálogo como um componente incorporável em uma IU maior, assim como um Fragment tradicional (como nas vezes em que a IU da caixa de diálogo deve aparecer de modos diferentes em telas grandes e pequenas).

As seções a seguir neste guia descrevem como usar um DialogFragment combinado com um objeto AlertDialog. Se quiser criar um seletor de data ou hora, leia o guia Seletores.

Observação: como a classe DialogFragment foi adicionada originalmente com o Android 3.0 (API de nível 11), este documento descreve como usar a classe DialogFragment fornecida com a Biblioteca de Suporte. Ao adicionar essa biblioteca ao aplicativo, é possível usar DialogFragment e uma variedade de outras APIs em dispositivos que executam o Android 1.6 ou versão mais recentes. Se a versão mínima compatível com seu aplicativo for a API de nível 11 ou mais recentes, será possível usar a versão de framework de DialogFragment, mas esteja ciente de que os links neste documento são para APIs da biblioteca de suporte. Ao usar a biblioteca de suporte, verifique se importou a classe android.support.v4.app.DialogFragment e não a android.app.DialogFragment.

Como criar um fragmento de caixa de diálogo

É possível criar vários designs de caixas de diálogo, inclusive layouts personalizados e outros descritos no guia de design Caixas de diálogo (link em inglês), estendendo DialogFragment e criando uma AlertDialog no método de callback onCreateDialog().

Por exemplo, veja a seguir uma AlertDialog básica gerenciada dentro de um 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. Caixa de diálogo com uma mensagem e dois botões de ação.

Agora, ao criar uma instância dessa classe e chamar show() nesse objeto, a caixa de diálogo será exibida como ilustrado na figura 1.

A próxima seção descreve em mais detalhes o uso das APIs AlertDialog.Builder para a criação de uma caixa de diálogo.

Conforme o nível de complexidade da caixa de diálogo, é possível implementar diversos outros métodos de callback no DialogFragment, inclusive todos os métodos de ciclo de vida de fragmentos básicos.

Construção de uma caixa de diálogo de alerta

A classe AlertDialog permite que você crie uma variedade de designs de caixas de diálogo, e geralmente é a única classe necessária. Como mostrado na figura 2, existem três regiões de uma caixa de diálogo de alerta:

Figura 2. Layout de uma caixa de diálogo.

  1. Título

    É opcional e deve ser usado somente quando a área do conteúdo estiver ocupada por uma mensagem detalhada, uma lista ou um layout personalizado. Se for necessário declarar uma mensagem ou pergunta simples (como a caixa de diálogo na figura 1), o título não é necessário.

  2. Área de conteúdo

    Pode exibir uma mensagem, uma lista ou outro layout personalizado.

  3. Botões de ação

    Não deve haver mais de três botões em uma caixa de diálogo.

A classe AlertDialog.Builder fornece APIs que permitem a criação de um AlertDialog com esses tipos de conteúdo, inclusive um layout personalizado.

Para criar um 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();

Os tópicos a seguir mostram como definir diversos atributos de caixas de diálogo com a classe AlertDialog.Builder.

Adição de botões

Para adicionar botões de ação como os da figura 2, chame os métodos setPositiveButton() e 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();

Os métodos set...Button() exigem um título para o botão (fornecido por um recurso de string) e um DialogInterface.OnClickListener que defina a ação a ser realizada quando o usuário pressionar o botão.

Há três botões de ação que podem ser adicionados:

Positivo
Você deve usar essa opção para aceitar e continuar a ação (a ação "OK").
Negativo
É o que se deve usar para cancelar a ação.
Indiferente
É o que se deve usar quando houver a opção do usuário não querer continuar a ação, mas não necessariamente cancelá-la. Ele aparece entre os botões positivo e negativo. Por exemplo, a ação pode ser "Lembrar mais tarde."

Somente é possível adicionar um dos tipos de cada botão a um AlertDialog. Ou seja, não é possível ter mais de um botão positivo.

Figura 3. Caixa de diálogo com um título e uma lista.

Adição de listas

Há três tipos de listas disponíveis nas APIs AlertDialog:

  • Lista de escolha única tradicional
  • Lista de escolha única persistente (botões de opção)
  • Lista de escolhas múltiplas persistentes (caixas de seleção)

Para criar uma lista de escolha única como a da figura 3, use o 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 a lista aparece na área do conteúdo da caixa de diálogo, a caixa não pode exibir uma mensagem e uma lista ao mesmo tempo, e será preciso definir um título para ela com setTitle(). Para especificar os itens da lista, chame setItems(), passando uma matriz. Como alternativa, é possível especificar uma lista usando setAdapter(). Isso permite retroceder a lista com dados dinâmicos (como os de um banco de dados) com um ListAdapter.

Se optar por retroceder a lista com um ListAdapter, use sempre um Loader para que o conteúdo seja carregado assincronamente. Veja mais detalhes sobre isso nos guias Criação de layouts com um adaptador e Carregadores.

Observação: por padrão, tocar em um item de lista dispensa a caixa de diálogo, a menos que você esteja usando uma das listas de opções persistentes a seguir.

Adição de uma lista de escolha única ou de múltipla escolha persistente

Para adicionar uma lista de itens de múltipla escolha (caixas de seleção) ou itens de escolha única (botões de opção), use os métodos setMultiChoiceItems() ou setSingleChoiceItems(), respectivamente.

Figura 4. Lista de itens de múltipla escolha.

Por exemplo, veja como criar uma lista de múltipla escolha como a ilustrada na figura 4, que salva os itens selecionados em um 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();
}

Embora uma lista tradicional e uma com botões de opção forneçam uma ação de "escolha única", use setSingleChoiceItems() se você quiser mantê-la. Ou seja, se você quiser que a abertura da caixa de diálogo novamente mais tarde indique a opção atual do usuário, crie uma lista com os botões de opção.

Criação de layout personalizado

Figura 5. Layout personalizado da caixa de diálogo.

Se você quiser um layout personalizado em uma caixa de diálogo, crie um layout e adicione-o a um AlertDialog chamando setView() no seu objeto AlertDialog.Builder.

Por padrão, o layout personalizado preenche a janela da caixa de diálogo, mas ainda é possível usar métodos AlertDialog.Builder para adicionar botões e um título.

Por exemplo, veja o arquivo de layout para a caixa de diálogo na 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>

Dica: por padrão, ao definir um elemento EditText para usar o tipo de entrada "textPassword", a família da fontes é definida como de fonte monoespaçada. Portanto, você deve alterar sua família de fontes para "sans-serif", de modo que ambos os campos de texto usem um estilo de fonte correspondente.

Para inflar o layout no DialogFragment, tenha um LayoutInflater com getLayoutInflater() e chame inflate(), em que o primeiro parâmetro é a identificação do recurso do layout e o segundo é uma exibição parental do layout. Você pode chamar setView() para colocar o layout na caixa de 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();
}

Dica: se você quiser uma caixa de diálogo personalizada, poderá exibir uma Activity como uma caixa de diálogo em vez de usar as APIs Dialog. Basta criar uma atividade e definir o tema como Theme.Holo.Dialog no elemento <activity> do manifesto:

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

É isso. Agora a atividade é exibida em uma janela da caixa de diálogo em vez de tela cheia.

Direcionamento de eventos de volta ao host da caixa de diálogo

Quando o usuário toca em um dos botões de ação da caixa de diálogo ou seleciona um item da lista, o DialogFragment pode realizar a ação necessária por conta própria, mas normalmente será preciso fornecer o evento à atividade ou ao fragmento que abriu a caixa de diálogo. Para fazer isso, defina uma interface com um método para cada tipo de evento de clique. Em seguida, implemente essa interface no componente host que receberá os eventos de ação do diálogo.

Por exemplo, veja um DialogFragment que define uma interface usada para a entrega de eventos de volta à atividade do 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");
        }
    }
    ...
}

A atividade que hospeda a caixa de diálogo cria uma instância da caixa com o construtor do fragmento da caixa de diálogo e recebe os eventos dela por um implementação da interface 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
        ...
    }
}

Como a atividade do host implementa o NoticeDialogListener, que é aplicado pelo método de callback onAttach() exibido acima, o fragmento da caixa de diálogo pode usar os métodos de callback da interface para entregar eventos de clique à atividade:

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

Exibição de uma caixa de diálogo

Para exibir a caixa de diálogo, crie uma instância do DialogFragment e chame show(), passando o FragmentManager e um nome de tag para o fragmento da caixa de diálogo.

Para ter o FragmentManager, chame getSupportFragmentManager() do FragmentActivity ou getFragmentManager() de um Fragment. Exemplo:

Kotlin

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

Java

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

O segundo argumento, "game", é um nome de tag exclusivo que o sistema usa para salvar e restaurar o estado do fragmento quando necessário. Para que a tag receba um identificador do fragmento, chame findFragmentByTag().

Exibição de uma caixa de diálogo em tela cheia ou como um fragmento incorporado

Talvez você tenha um projeto de IU em que uma parte dela apareça como uma caixa de diálogo em determinadas situações, mas como tela cheia ou fragmento incorporado em outras (dependendo do tamanho da tela do dispositivo). A classe DialogFragment oferece essa flexibilidade porque ainda pode se comportar como um Fragment incorporável.

Contudo, não é possível usar AlertDialog.Builder nem outros objetos Dialog para criar a caixa de diálogo nesse caso. Se quiser que o DialogFragment seja incorporável, defina a IU da caixa de diálogo em um layout e carregue o layout no callback onCreateView().

Veja um exemplo de DialogFragment que pode aparecer tanto como caixa de diálogo quanto como fragmento incorporável (usando um layout chamado 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 seguir, veja alguns códigos que decidem por exibir o fragmento como uma caixa de diálogo ou como uma IU de tela cheia, com base no tamanho da tela:

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 ver mais informações sobre a realização de transações de fragmentos, consulte o guia Fragmentos.

Nesse exemplo, o booleano mIsLargeLayout especifica se o dispositivo atual deve usar o projeto de layout grande do aplicativo e exibir esse fragmento como uma caixa de diálogo em vez de tela cheia. O melhor modo de definir esse tipo de booleano é declarar um valor de recurso bool com um valor de recurso alternativo para diferentes tamanhos de tela. Por exemplo, veja duas versões de recurso bool para diferentes tamanhos de tela:

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>

Assim, é possível inicializar o valor mIsLargeLayout durante o método onCreate() da atividade:

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

Exibição de uma atividade como uma caixa de diálogo em telas grandes

Em vez de exibir uma caixa de diálogo como uma IU de tela cheia em telas pequenas, é possível ter o mesmo resultado exibindo um Activity como uma caixa de diálogo em telas grandes. A abordagem escolhida depende do projeto do aplicativo, mas a exibição de uma atividade como caixa de diálogo normalmente é útil quando o aplicativo já está projetado para telas pequenas e é preciso melhorar a experiência em tablets exibindo uma atividade de vida curta como uma caixa de diálogo.

Para exibir uma atividade como uma caixa de diálogo somente em telas grandes, aplique o tema Theme.Holo.DialogWhenLarge no elemento <activity> do manifesto:

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

Para ver mais informações sobre como estilizar as atividades com temas, consulte o guia Estilos e temas.

Dispensa de uma caixa de diálogo

Quando o usuário toca em qualquer botão de ação criado com um AlertDialog.Builder, o sistema dispensa a caixa de diálogo.

O sistema também dispensa a caixa de diálogo quando o usuário toca em um item em uma lista da caixa de diálogo, exceto quando a lista usa botões de opção ou caixas de seleção. Caso contrário, será possível dispensá-la manualmente chamando dismiss() no DialogFragment.

Caso seja necessário realizar determinadas ações quando a caixa de diálogo é dispensada, será possível implementar o método onDismiss() no DialogFragment.

Também é possível cancelar uma caixa de diálogo. Esse é um evento especial que indica que o usuário deixou explicitamente a caixa de diálogo sem concluir a tarefa. Isso ocorre se o usuário pressionar o botão Voltar, tocar na tela fora da área da caixa de diálogo ou se você chamar cancel() explicitamente no Dialog (como em resposta a um botão Cancelar na caixa de diálogo).

Como mostrado no exemplo acima, é possível responder ao evento de cancelamento implementando onCancel() na classe DialogFragment.

Observação: o sistema chama o onDismiss() em cada evento que invoca o callback onCancel(). Entretanto, se você chamar Dialog.dismiss() ou DialogFragment.dismiss(), o sistema chamará onDismiss(), mas não onCancel(). Portanto, em geral, é preciso chamar dismiss() quando o usuário pressiona o botão positivo na caixa de diálogo para removê-la da exibição.