Как показывать диалоговые окна с помощью DialogFragment

DialogFragment – это специальный подкласс фрагментов, предназначенный для создания и размещения диалоговых окон. Размещать диалоговое окно во фрагменте необязательно, но это позволяет FragmentManager управлять состоянием диалогового окна и автоматически восстанавливать его при изменении конфигурации.

Создание DialogFragment

Чтобы создать DialogFragment, создайте класс, расширяющий DialogFragment, и переопределите onCreateDialog(), как показано в примере ниже.

Kotlin

class PurchaseConfirmationDialogFragment : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
            AlertDialog.Builder(requireContext())
                .setMessage(getString(R.string.order_confirmation))
                .setPositiveButton(getString(R.string.ok)) { _,_ -> }
                .create()

    companion object {
        const val TAG = "PurchaseConfirmationDialog"
    }
}

Java

public class PurchaseConfirmationDialogFragment extends DialogFragment {
   @NonNull
   @Override
   public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
       return new AlertDialog.Builder(requireContext())
               .setMessage(getString(R.string.order_confirmation))
               .setPositiveButton(getString(R.string.ok), (dialog, which) -> {} )
               .create();
   }

   public static String TAG = "PurchaseConfirmationDialog";
}

Подобно тому, как onCreateView() создает корневой элемент View в обычном фрагменте, onCreateDialog() создает Dialog для отображения в качестве части DialogFragment. DialogFragment обрабатывает показ Dialog в подходящих состояниях жизненного цикла фрагмента.

Как и в случае с onCreateView(), вы можете вернуть любой подкласс Dialog из onCreateDialog() и не ограничены использованием AlertDialog.

Показ DialogFragment

Вам не нужно вручную создавать FragmentTransaction, чтобы показывать DialogFragment. Вместо этого используйте метод show(). Вы можете передать ссылку на FragmentManager и String, чтобы использовать их в качестве тега FragmentTransaction.

При создании DialogFragment внутри Fragment используйте дочерний FragmentManager фрагмента, чтобы состояние правильно восстанавливалось после изменения конфигурации. Если тег не равен null, вы можете использовать findFragmentByTag(), чтобы получить DialogFragment позже.

Kotlin

// From another Fragment or Activity where you wish to show this
// PurchaseConfirmationDialogFragment.
PurchaseConfirmationDialogFragment().show(
     childFragmentManager, PurchaseConfirmationDialog.TAG)

Java

// From another Fragment or Activity where you wish to show this
// PurchaseConfirmationDialogFragment.
new PurchaseConfirmationDialogFragment().show(
       getChildFragmentManager(), PurchaseConfirmationDialog.TAG);

Чтобы лучше контролировать FragmentTransaction, можно использовать перегрузку show(), которая принимает существующий FragmentTransaction.

Жизненный цикл DialogFragment

DialogFragment следует стандартному жизненному циклу фрагмента с несколькими дополнительными обратными вызовами. Вот самые распространенные из них:

  • onCreateDialog(): переопределите этот обратный вызов, чтобы предоставить Dialog для управления фрагментом и его отображения.
  • onDismiss(). Переопределите этот обратный вызов, если вам нужно выполнить какую-либо пользовательскую логику при закрытии Dialog, например освободить ресурсы или отменить подписку на наблюдаемые ресурсы.
  • onCancel() – переопределите этот обратный вызов, если вам нужно выполнить какую-либо пользовательскую логику при отмене Dialog.

DialogFragment также содержит методы для закрытия или настройки возможности отмены DialogFragment:

  • dismiss() – закрыть фрагмент и его диалоговое окно. Если фрагмент был добавлен в обратный стек, все состояния обратного стека вплоть до этой записи включительно извлекаются. В противном случае для удаления фрагмента выполняется новая транзакция.
  • setCancelable() – определяет, можно ли отменить показ Dialog. Используйте этот метод вместо прямого вызова Dialog.setCancelable(boolean).

При использовании DialogFragment с Dialog вы не переопределяете onCreateView() или onViewCreated(). Диалоги – это не просто представления, у них есть собственное окно. Поэтому он не может переопределить onCreateView(). Кроме того, метод onViewCreated() никогда не вызывается для пользовательского объекта DialogFragment, если вы не переопределили метод onCreateView() и не предоставили ненулевой объект View.

Как использовать настраиваемые представления

Вы можете создать DialogFragment и показать диалоговое окно, переопределив onCreateView(). Вы можете указать layoutId, как для обычного фрагмента, или использовать конструктор DialogFragment.

Значение View, возвращенное методом onCreateView(), автоматически добавляется в диалоговое окно. В большинстве случаев это означает, что вам не нужно переопределять onCreateDialog(), поскольку пустое диалоговое окно по умолчанию заполняется вашим представлением.

Некоторые подклассы DialogFragment, например BottomSheetDialogFragment, встраивают представление в диалоговое окно, оформленное как нижний экран.