Диалоги

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

Дизайн диалогов. Подробнее о дизайне диалоговых окон читайте в разделе Диалоги руководства по дизайну.

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

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

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

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

Примечание: поскольку оригинальный класс DialogFragment был добавлен в Android 3.0 (API 11), далее будет описано использование класса DialogFragment из библиотеки поддержки. При использовании библиотеки поддержки убедитесь, что импортируете android.support.v4.app.DialogFragment вместо android.app.DialogFragment.

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

Вы можете создавать различный дизайн диалогов, расширив класс DialogFragment и создав объект типа AlertDialog в методе обратного вызова onCreateDialog().

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

Теперь нужно создать экземпляр данного класса и вызвать метод show(). Отобразится диалог, представленный на рисунке 1.

Рисунок 1. Диалог с двумя кнопками.

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

Создание Alert диалога

Класс AlertDialog позволяет создавать диалоги различного вида и часто для создания диалогов другие классы не требуются. Как показано на рисунке 2, диалог делится на три области:

Рисунок 2.Разметка диалога.

  1. Заголовок

    Не является обязательным и должен использовать только когда область данных занята подробным описанием, списком или разметкой. Если нужно вывести простое сообщение или вопрос (как на рисунке 1), заголовок не нужен.

  2. Область данных

    В области данных может отображаться сообщение, список или какая-либо разметка.

  3. Кнопки

    В диалоге не должно быть больше трех кнопок!

Класс AlertDialog.Builder предоставляет API, позволяющее создать объект типа AlertDialog со всеми необходимыми данными, включая разметку.

Для создания объекта AlertDialog проделайте следующее:

Дальше мы рассмотрим как устанавливать различные параметры диалога с помощью класса AlertDialog.Builder.

Добавляем кнопки

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

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

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

Positive (положительная)
Используйте эту кнопку для подтверждения или продолжения действия (в роли кнопки “ОК”).
Negative (отрицательная)
Используйте эту кнопку для отмены действия.
Neutral (нейтральная)
Используйте эту кнопку, когда пользователь может не желать продолжать действие, но и не уверен в его отмене. Кнопка появляется между положительной и отрицательной. Например, это может быть кнопка “Напомнить позже”.

Вы можете добавить только одну из кнопок каждого типа.

Добавление списка

Есть три типа списков, доступных в классе AlertDialog:

Рисунок 3.Диалог с заголовком и традиционным списком.

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

Для создания традиционного диалога, как на рисунке 3, используйте метод setItems():

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

Если вы решили заполнить список с применением адаптера, всегда используйте класс Loader, чтобы загружать данные асинхронно. Подробнее об этом читайте в разделах Разметка и Loaders.

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

Добавление постоянного списка с одиночным или множественным выбором.

Рисунок 4.Диалог с множественным выбором.

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

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

Хотя и традиционный и постоянный списки дают возможность выбрать один пункт, при использовании постоянного списка вы должны использовать метод setSingleChoiceItems(), чтобы сохранить выбор пользователя. Тогда при повторном открытии диалога выбранный ранее элемент списка будет помечен.

Создание произвольной разметки

Рисунок 5.Диалог с произвольной разметкой.

Чтобы создать произвольную разметку диалога, используйте метод setView() объекта AlertDialog.Builder.

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

Ниже приведен пример создания разметки для диалога, представленного на рисунке 5:

res/layout/dialog_signin.xml

Совет: по умолчанию при назначении элементу EditText типа "textPassword", устанавливается шрифт "monospace". Поэтому необходимо вручную назначить шрифт "sans-serif“, чтобы все поля выглядели одинаково.

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

Совет: если вы хотите создать произвольный диалог, вы можете также просто создать явление (Activity) с произвольной разметкой и установить для нее тему Theme.Holo.Dialog в файле манифеста:

Передача событий в компонент, создавший диалог

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

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

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

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

Отображение диалога

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

Вы можете получить экземпляр FragmentManager с помощью метода getSupportFragmentManager() класса getFragmentManager() класса Fragment. Например:

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

Отображение диалога на весь экран и встраиваемые диалоги

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

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

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

А также еще один один пример когда, который решает в каком виде отображать диалог в зависимости от размера экрана:

Подробнее о транзакциях фрагментов смотрите в разделе Фрагменты.

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

res/values/bools.xml

res/values-large/bools.xml

После чего можно инициализировать значение переменной в методе onCreate():

Отображение явления в форме диалога на больших экранах

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

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

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

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

Система также закрывает диалог при щелчке по традиционному списку (когда он не содержит флажки и радио-кнопки). Вы можете вручную закрыть диалог с помощью метода dismiss().

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

Вы можете также отменить диалог. Это особое событие, которое показывает, что пользователь покинул диалог не завершив задачу. Такое случается при нажатии кнопки “Назад”, при нажатии экрана вне области диалога или при вызове метода cancel().

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

Примечание: система вызывает метод onDismiss() при каждом событии, вызывающем onCancel(). Однако, если вы вызываете метод Dialog.dismiss() или DialogFragment.dismiss(), система вызовет только метод onDismiss(), но не onCancel(). Поэтому вы должны вызывать dismiss() когда пользователь нажимает позитивную кнопку, чтобы закрыть диалог.

Добавить комментарий