Добрый день/вечер/утро, уважаемые читатели и Вы, %username%!
Я занимаюсь разработкой приложений для Android, обожаю эту операционную систему и хочу поделиться своим опытом использования в своих проектах диалоговых окон. В первую очередь эта статья записка очень пригодится начинающим в области разработки для Android.
Также для новичков в этой отрасли рекомендую сперва прочитать вот этот пост уважаемого Hoorsh.
А теперь приступим к рассмотрению данного вопроса (у которого есть несколько подводных камней) под катом.
Dialog
Dialog — это класс, принадлежащий Android SDK и помогающий нам, простым смертным программистам, работать с диалоговыми окнами в Android. Класс Dialog имеет 4 подкласса:
- AlertDialog: это диалоговое окно для различных сообщений приложения, например «Вы хотите купить мое приложение?» или что то в этом роде. AlertDialog поддерживает три кнопки — утвердительную (OK), отрицательную (Cancel) и нейтральную (Later).
- ProgressDialog: это диалоговое окно для отображения выполнения различных процессов, загрузки, например.
- DatePickerDialog: диалоговое окно предлагает пользователю выбрать дату.
- TimePickerDialog: диалоговое окно предлагает пользователю выбрать время
На первом из этого списка, AlertDialog мы и остановимся подробнее.
AlertDialog
Чтобы создать диалоговое окно AlertDialog нам в помощь потребуется экземпляр класса Builder:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Теперь, когда у нас есть builder, мы можем «строить» свое собственное диалоговое окно. В параметры диалогового окна Вы можете написать множество различных параметров, но основными являются эти:
- setTitle(int resID) — задает заголовок диалогового окна, принимает в качестве аргументов ссылку на ресурс или строку.
- setMessage(int resID) — задает сообщение в диалоговом окне, также принимает ссылку на ресурс или строку.
- setPositiveButton(int textID, DialogInterface.OnClickListener listener) — устанавливает на Вашем диалоговом окне утвердительную кнопку с текстом ресурса textID и слушателем listener. Методы setNegativeButton и setNeutralButton идентичны, с разницей в назначении кнопок.
Пример создания AlertDialog:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.dialog_about_title);
builder.setMessage(R.string.dialog_about_message);
builder.setCancelable(true);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { // Кнопка ОК
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss(); // Отпускает диалоговое окно
}
});
AlertDialog dialog = builder.create();
В этом примере я использовал setCancelable(true) — это разрешает пользователю закрывать диалоговое окно с помощью хардварной кнопки Back. Еще я создал слушателя для утвердительной кнопки и использовал метод create(). Метод create() возвращает готовое диалоговое окно с вашими параметрами как экземпляр класса AlertDialog.
Вот мы и создали диалоговое окно! Следующая задача — показать его пользователю. Вот тут есть несколько вариантов:
- showDialog(AlertDialog dialog) — самый простой способ показать диалоговое окно, но начиная с версии 3.0 разработчики Android не рекомендуют пользоваться этим методом, и в результате вы получите предупреждение, которое можно обойти только @SurpressWarning, что есть не совсем хорошо.
- AlertDialog dialog.show() — альтернативный способ показать окно, для этого в экземпляре dialog должен лежать результат метода Builder.create().
Второй метод нам подходит больше, но писать в основной активности кучу различных Buider и AlertDialog портит читабельность кода. Поэтому целесообразней вынести создание и обработку диалоговых окон в новый класс, например:
public class DialogScreen {
public static final int IDD_ABOUT = 1; // Идентификаторы диалоговых окон
public static final int IDD_SETTINGS = 2;
public static final int IDD_RATE = 3;
public static AlertDialog getDialog(Activity activity, int ID) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
switch(ID) {
case IDD_ABOUT: // Диалоговое окно About
builder.setTitle(R.string.dialog_about_title);
builder.setMessage(R.string.dialog_about_message);
builder.setCancelable(true);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { // Кнопка ОК
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss(); // Отпускает диалоговое окно
}
});
return builder.create();
case IDD_RATE: // Диалоговое окно Rate the app
builder.setTitle(R.string.dialog_rate_title);
builder.setMessage(R.string.dialog_rate_message);
builder.setCancelable(true);
builder.setPositiveButton(R.string.dialog_rate_ok, new DialogInterface.OnClickListener() { // Переход на оценку приложения
@Override
public void onClick(DialogInterface dialog, int which) {
// Переход
dialog.dismiss();
}
});
builder.setNeutralButton(R.string.dialog_rate_cancel, new DialogInterface.OnClickListener() { // Оценить приложение потом
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss(); // Отпускает диалоговое окно
}
});
builder.setNegativeButton(R.string.dialog_rate_buy, new DialogInterface.OnClickListener() { // Переход на покупку AdFree версии
@Override
public void onClick(DialogInterface dialog, int which) {
// Переход
dialog.dismiss();
}
});
return builder.create();
case IDD_SETTINGS: // Диалог настроек
View view = activity.getLayoutInflater().inflate(R.layout.settings, null); // Получаем layout по его ID
builder.setView(view);
builder.setTitle(R.string.dialog_settings_title);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { // Кнопка ОК
public void onClick(DialogInterface dialog, int whichButton) {
MainActivity.doSaveSettings(); // Переход в сохранение настроек MainActivity
dialog.dismiss();
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { // Кнопка Отмена
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setCancelable(true);
return builder.create();
default:
return null;
}
}
}
Единственная заметка по поводу этого кода будет про использования метода setView(View view) в диалоге IDD_SETTINGS. У AlertDialog как и у всех остальных диалоговых окон есть одна приятная особенность — им можно задавать собственные Layout, что позволяет полностью видоизменять диалоговые окна и их содержимое. Здесь есть один подводный камень: обработку элементов этого Layout вы должны будете производить именно в той Activity, где вызываете это диалоговое окно. Например я показываю диалоговое окно IDD_SETTINGS в MainActivity с Layout по имени settings:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<SeekBar
android:id="@+id/seekVol"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/seekSense"
android:layout_marginTop="42dp" />
<TextView
android:id="@+id/textVol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/seekSense"
android:layout_marginTop="20dp"
android:text="@string/dialog_settings_vol"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/textSense"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="@string/dialog_settings_sense"
android:textAppearance="?android:attr/textAppearanceMedium" />
<SeekBar
android:id="@+id/seekSense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textSense" />
</RelativeLayout>
Соответственно я загружаю это окно в MainActivity:
AlertDialog dialog = DialogScreen.getDialog(this, DialogScreen.IDD_SETTINGS);
dialog.show();
initSettings(dialog);
}
Метод initSettings класса MainActivity в данном случае будет выглядеть так:
// Определяем SeekBar и привязываем к нему дельты настроек
SeekBar sb_sense = (SeekBar)dialog.findViewById(R.id.seekSense);
SeekBar sb_vol = (SeekBar)dialog.findViewById(R.id.seekVol);
// Задаем этим SeekBar текущие значения настроек
sb_sense.setProgress(sense);
sb_vol.setProgress(volume);
Ну а дальше обрабатываете свои объекты как вам угодно.
Небольшой итог
1) Для большинства целей диалоговых окон подходит AlertDialog
2) AlertDialog может принимать вид layout с любыми объектами
3) Гораздо лучше использовать для диалоговых окон отдельный класс и пользоваться AlertDialog.show()
4) Обработка объектов кастомного layout производится в активности, вызвавшей диалог
В следующей части этой статьи пойдет речь о DialogFragment, который был включен в Android SDK начиная с 3.0 Honeycomb. Надеюсь эта статья поможет новичкам и не очень в своих квестах по завоеванию Google Play.
P.S.
Это моя первая статья для хабра, поэтому принимаю любую конструктивную критику. Заранее спасибо.
Автор: Alviere