Диалоги

Попробуйте способ создания
Jetpack Compose — рекомендуемый набор инструментов пользовательского интерфейса для Android. Узнайте, как добавлять компоненты в Compose.

Диалог — это небольшое окно, предлагающее пользователю принять решение или ввести дополнительную информацию. Диалоговое окно не заполняет экран и обычно используется для модальных событий, требующих от пользователей выполнения действия, прежде чем они смогут продолжить.

Изображение, показывающее базовый диалог
Рисунок 1. Базовый диалог.

Класс Dialog является базовым классом для диалогов, но не создает экземпляр Dialog напрямую. Вместо этого используйте один из следующих подклассов:

AlertDialog
Диалоговое окно, в котором может отображаться заголовок, до трех кнопок, список выбираемых элементов или пользовательский макет.
DatePickerDialog или TimePickerDialog
Диалоговое окно с предопределенным пользовательским интерфейсом, позволяющее пользователю выбрать дату или время.

Эти классы определяют стиль и структуру вашего диалога. Вам также понадобится DialogFragment в качестве контейнера для вашего диалога. Класс DialogFragment предоставляет все элементы управления, необходимые для создания диалогового окна и управления его внешним видом, вместо вызова методов объекта Dialog .

Использование DialogFragment для управления диалогом позволяет правильно обрабатывать события жизненного цикла, например, когда пользователь нажимает кнопку «Назад» или поворачивает экран. Класс DialogFragment также позволяет повторно использовать пользовательский интерфейс диалогового окна в качестве встраиваемого компонента в более крупном пользовательском интерфейсе — точно так же, как традиционный Fragment — например, когда вы хотите, чтобы пользовательский интерфейс диалогового окна по-разному отображался на больших и маленьких экранах.

В следующих разделах этого документа описано, как использовать DialogFragment в сочетании с объектом AlertDialog . Если вы хотите создать средство выбора даты или времени, прочтите статью Добавление средств выбора в ваше приложение .

Создать фрагмент диалога

Вы можете реализовать самые разнообразные конструкции диалогов, включая пользовательские макеты и макеты, описанные в разделе «Диалоги дизайна материалов» , расширив DialogFragment и создав AlertDialog в методе обратного вызова onCreateDialog() .

Например, вот базовый AlertDialog , управляемый внутри DialogFragment :

Котлин

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("Start game")
                .setPositiveButton("Start") { dialog, id ->
                    // START THE GAME!
                }
                .setNegativeButton("Cancel") { dialog, id ->
                    // User cancelled the dialog.
                }
            // Create the AlertDialog object and return it.
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

class OldXmlActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_old_xml)

        StartGameDialogFragment().show(supportFragmentManager, "GAME_DIALOG")
    }
}

Ява

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 cancels the dialog.
                   }
               });
        // Create the AlertDialog object and return it.
        return builder.create();
    }
}
// ...

StartGameDialogFragment().show(supportFragmentManager, "GAME_DIALOG");

Когда вы создаете экземпляр этого класса и вызываете функцию show() для этого объекта, диалоговое окно появляется, как показано на следующем рисунке.

Изображение, показывающее базовое диалоговое окно с двумя кнопками действий.
Рисунок 2. Диалог с сообщением и двумя кнопками действий.

В следующем разделе представлены более подробные сведения об использовании API AlertDialog.Builder для создания диалогового окна.

В зависимости от того, насколько сложен ваш диалог, вы можете реализовать множество других методов обратного вызова в DialogFragment , включая все базовые методы жизненного цикла фрагмента .

Создайте диалоговое окно оповещения

Класс AlertDialog позволяет создавать различные варианты оформления диалогов и часто является единственным необходимым классом диалогов. Как показано на следующем рисунке, диалоговое окно предупреждения состоит из трех областей:

  • Заголовок: это необязательно и используется только в том случае, если область содержимого занята подробным сообщением, списком или пользовательским макетом. Если вам нужно изложить простое сообщение или вопрос, заголовок не нужен.
  • Область содержимого: здесь может отображаться сообщение, список или другой пользовательский макет.
  • Кнопки действий: в диалоговом окне может быть до трех кнопок действий.

Класс AlertDialog.Builder предоставляет API, которые позволяют создавать AlertDialog с содержимым такого типа, включая настраиваемый макет.

Чтобы построить AlertDialog , сделайте следующее:

Котлин

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setMessage("I am the message")
    .setTitle("I am the title")

val dialog: AlertDialog = builder.create()
dialog.show()

Ява

// 1. Instantiate an AlertDialog.Builder 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 AlertDialog.
AlertDialog dialog = builder.create();

The previous code snippet generates this dialog:

Изображение, показывающее диалоговое окно с заголовком, областью содержимого и двумя кнопками действий.
Figure 3. The layout of a basic alert dialog.

Добавить кнопки

Чтобы добавить кнопки действий, подобные показанным на рисунке 2, вызовите методы setPositiveButton() и setNegativeButton() :

Котлин

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setMessage("I am the message")
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Ява

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 taps OK button.
           }
       });
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // User cancels the dialog.
           }
       });
// Set other dialog properties.
...

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

Методам set...Button() требуется заголовок кнопки, предоставленный строковым ресурсом , и DialogInterface.OnClickListener , определяющий действие, которое необходимо выполнить, когда пользователь нажимает кнопку.

Вы можете добавить три кнопки действий:

  • Положительный: используйте это, чтобы принять и продолжить действие (действие «ОК»).
  • Отрицательный: используйте это, чтобы отменить действие.
  • Нейтрально: используйте это, когда пользователь не хочет продолжать действие, но не обязательно хочет его отменить. Он появляется между положительными и отрицательными кнопками. Например, действием может быть «Напомнить мне позже».

В AlertDialog можно добавить только одну кнопку каждого типа. Например, у вас не может быть более одной «положительной» кнопки.

Предыдущий фрагмент кода отображает диалоговое окно предупреждения, подобное следующему:

Изображение, показывающее диалоговое окно оповещения с заголовком, сообщением и двумя кнопками действий.
Рисунок 4. Диалоговое окно предупреждения с заголовком, сообщением и двумя кнопками действий.

Добавить список

В API AlertDialog доступны три типа списков:

  • Традиционный список с одним выбором.
  • Постоянный список с одним выбором (переключатели).
  • Постоянный список с множественным выбором (флажками).

Чтобы создать список с одним выбором, подобный показанному на рисунке 5, используйте метод setItems() :


Котлин

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setItems(arrayOf("Item One", "Item Two", "Item Three")) { dialog, which ->
        // Do something on item tapped.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Ява

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

Этот фрагмент кода создает диалоговое окно, подобное следующему:

Изображение, показывающее диалоговое окно с заголовком и списком.
Рисунок 5. Диалог с заголовком и списком.

Поскольку список отображается в области содержимого диалогового окна, диалоговое окно не может отображать одновременно сообщение и список. Установите заголовок диалога с помощью setTitle() . Чтобы указать элементы для списка, вызовите setItems() , передав массив. Альтернативно вы можете указать список с помощью setAdapter() . Это позволяет подкрепить список динамическими данными (например, из базы данных) с помощью ListAdapter .

Если вы поддерживаете свой список с помощью ListAdapter , всегда используйте Loader , чтобы контент загружался асинхронно. Это описано далее в разделе Сборка макетов с помощью адаптера и загрузчиков .

Добавить постоянный список с множественным или одним выбором

Чтобы добавить список элементов с множественным выбором (флажки) или элементов с одним выбором (переключатели), используйте методы setMultiChoiceItems() или setSingleChoiceItems() соответственно.

Например, вот как можно создать список с множественным выбором, подобный показанному на рисунке 6, который сохраняет выбранные элементы в ArrayList :

Котлин

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setMultiChoiceItems(
        arrayOf("Item One", "Item Two", "Item Three"), null) { dialog, which, isChecked ->
        // Do something.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Ява

@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 checks the item, add it to the selected
                       // items.
                       selectedItems.add(which);
                   } else if (selectedItems.contains(which)) {
                       // 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 taps OK, so save the selectedItems results
                   // somewhere or return them to the component that opens the
                   // dialog.
                   ...
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   ...
               }
           });

    return builder.create();
}
Изображение, показывающее диалоговое окно, содержащее список элементов с множественным выбором.
Рисунок 6. Список элементов с несколькими вариантами ответов.

Диалоговое окно предупреждения с одним выбором можно получить следующим образом:

Котлин

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setSingleChoiceItems(
        arrayOf("Item One", "Item Two", "Item Three"), 0
    ) { dialog, which ->
        // Do something.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Ява

        String[] choices = {"Item One", "Item Two", "Item Three"};
        
        AlertDialog.Builder builder = AlertDialog.Builder(context);
        builder
                .setTitle("I am the title")
                .setPositiveButton("Positive", (dialog, which) -> {

                })
                .setNegativeButton("Negative", (dialog, which) -> {

                })
                .setSingleChoiceItems(choices, 0, (dialog, which) -> {

                });

        AlertDialog dialog = builder.create();
        dialog.show();

This results in the following example:

Изображение, показывающее диалоговое окно, содержащее список элементов с одним выбором.
Рисунок 7. Список элементов с одним выбором.

Создайте индивидуальный макет

Если вам нужен собственный макет в диалоговом окне, создайте макет и добавьте его в AlertDialog вызвав setView() для вашего объекта AlertDialog.Builder .

Изображение, показывающее настраиваемый макет диалогового окна.
Рисунок 8. Пользовательский макет диалогового окна.

По умолчанию пользовательский макет заполняет диалоговое окно, но вы все равно можете использовать методы AlertDialog.Builder для добавления кнопок и заголовка.

Например, вот файл макета для предыдущего макета пользовательского диалога:

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>

Чтобы раздуть макет в DialogFragment , получите LayoutInflater с помощью getLayoutInflater() и вызовите inflate() . Первый параметр — это идентификатор ресурса макета, а второй параметр — родительское представление макета. Затем вы можете вызвать setView() , чтобы поместить макет в диалоговое окно. Это показано в следующем примере.

Котлин

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 it's 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")
}

Ява

@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 it's 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();
}

Если вам нужен собственный диалог, вы можете вместо этого отображать Activity в виде диалога вместо использования API-интерфейсов Dialog . Создайте активность и установите ее тему Theme.Holo.Dialog в элементе манифеста <activity> :

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

Действие теперь отображается в диалоговом окне, а не в полноэкранном режиме.

Передавать события обратно узлу диалога

Когда пользователь нажимает одну из кнопок действий диалогового окна или выбирает элемент из его списка, ваш DialogFragment может сам выполнить необходимое действие, но часто вы хотите доставить событие в действие или фрагмент, открывающий диалоговое окно. Для этого определите интерфейс с методом для каждого типа события щелчка. Затем реализуйте этот интерфейс в ведущем компоненте, который получает события действия из диалогового окна.

Например, вот DialogFragment , определяющий интерфейс, через который он доставляет события обратно активности узла:

Котлин

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 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 you 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"))
        }
    }
}

Ява

public class NoticeDialogFragment extends DialogFragment {

    // The activity that creates an instance of this dialog fragment must
    // implement this interface 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 you 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");
        }
    }
    ...
}

Действие, содержащее диалог, создает экземпляр диалога с конструктором фрагмента диалога и получает события диалога посредством реализации интерфейса NoticeDialogListener :

Котлин

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 taps the dialog's positive button.
    }

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

Ява

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 taps the dialog's positive button.
        ...
    }

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

Поскольку действие узла реализует NoticeDialogListener , который реализуется методом обратного вызова onAttach() , показанным в предыдущем примере, фрагмент диалога может использовать методы обратного вызова интерфейса для доставки событий щелчка в действие:

Котлин

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

Ява

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

Показать диалог

Если вы хотите отобразить свой диалог, создайте экземпляр вашего DialogFragment и вызовите show() , передав FragmentManager и имя тега для фрагмента диалога.

Вы можете получить FragmentManager , вызвав getSupportFragmentManager() из FragmentActivity или вызвав getParentFragmentManager() из Fragment . См. следующий пример:

Котлин

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

Ява

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

Второй аргумент, "game" , — это уникальное имя тега, которое система использует для сохранения и восстановления состояния фрагмента при необходимости. Тег также позволяет вам получить дескриптор фрагмента, вызвав findFragmentByTag() .

Показывать диалог в полноэкранном режиме или в виде встроенного фрагмента

Возможно, вам захочется, чтобы часть вашего дизайна пользовательского интерфейса отображалась в виде диалогового окна в одних ситуациях и в виде полноэкранного или встроенного фрагмента в других. Вы также можете захотеть, чтобы оно отображалось по-разному в зависимости от размера экрана устройства. Класс DialogFragment предлагает гибкость для достижения этой цели, поскольку он может вести себя как встраиваемый Fragment .

Однако в этом случае вы не можете использовать AlertDialog.Builder или другие объекты Dialog для построения диалога. Если вы хотите, чтобы DialogFragment был встраиваемым, определите пользовательский интерфейс диалогового окна в макете, а затем загрузите макет в обратном вызове onCreateView() .

Вот пример DialogFragment , который может отображаться как диалог или встраиваемый фрагмент, используя макет с именем purchase_items.xml :

Котлин

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 a 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 the dialog characteristics. For example,
        // the dialog includes a title by default, but your custom layout might
        // not need it. 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
    }
}

Ява

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 a 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 the dialog characteristics. For example,
        // the dialog includes a title by default, but your custom layout might
        // not need it. 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;
    }
}

В следующем примере определяется, следует ли отображать фрагмент в виде диалогового окна или полноэкранного пользовательского интерфейса в зависимости от размера экрана:

Котлин

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 polished look, 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()
    }
}

Ява

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

Дополнительные сведения о выполнении транзакций фрагментов см. в разделе Фрагменты .

В этом примере логическое значение mIsLargeLayout указывает, должно ли текущее устройство использовать большой дизайн макета приложения и, таким образом, отображать этот фрагмент в виде диалогового окна, а не в полноэкранном режиме. Лучший способ установить такое логическое значение — объявить значение ресурса bool с альтернативным значением ресурса для разных размеров экрана. Например, вот две версии ресурса bool для разных размеров экрана:

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>

Затем вы можете инициализировать значение mIsLargeLayout во время метода onCreate() действия, как показано в следующем примере:

Котлин

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

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

Ява

boolean isLargeLayout;

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

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

Показывать действие в виде диалога на больших экранах

Вместо отображения диалогового окна в виде полноэкранного пользовательского интерфейса на маленьких экранах вы можете получить тот же результат, отображая Activity в виде диалогового окна на больших экранах. Выбранный вами подход зависит от дизайна вашего приложения, но отображение действия в виде диалогового окна часто полезно, если ваше приложение разработано для маленьких экранов и вы хотите улучшить его работу на планшетах, показывая кратковременное действие в виде диалогового окна.

Чтобы отображать действие в виде диалога только на больших экранах, примените тему Theme.Holo.DialogWhenLarge к элементу манифеста <activity> :

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

Дополнительные сведения о стилизации действий с помощью тем см. в разделе Стили и темы .

Закрыть диалог

Когда пользователь нажимает кнопку действия, созданную с помощью AlertDialog.Builder , система закрывает диалоговое окно.

Система также закрывает диалоговое окно, когда пользователь касается элемента в списке диалоговых окон, за исключением случаев, когда в списке используются переключатели или флажки. В противном случае вы можете закрыть диалоговое окно вручную, вызвав dismiss() в DialogFragment .

Если вам нужно выполнить определенные действия, когда диалог закрывается, вы можете реализовать метод onDismiss() в своем DialogFragment .

Вы также можете отменить диалог. Это специальное событие, которое указывает на то, что пользователь покидает диалог, не выполнив задачу. Это происходит, если пользователь нажимает кнопку «Назад» или касается экрана за пределами области диалогового окна, или если вы явно вызываете cancel() в Dialog , например, в ответ на кнопку «Отмена» в диалоговом окне.

Как показано в предыдущем примере, вы можете отреагировать на событие отмены, реализовав onCancel() в своем классе DialogFragment .