Содержание
Диалоги — это очень удобный и приятный для пользователя способ взаимодействия с приложением. Но при их использовании разработчик может столкнуться с некоторыми трудностями при смене ориентации экрана и иных переменах в жизненном цикле приложения. Давайте рассмотрим как разработчики Android SDK помогли нам с этой проблемой.
Методы и коллбэки Activity для работы с диалогами
Всего нужно знать 5 методов, описанных в таблице ниже. Применение этих методов гарантирует, что Activity, у которой они вызывались, берет на себя управление этими диалогами, а значит нам об этом больше париться не надо (почти). При создании диалогов таким образом для них вызывается метод setOwnerActivity(Activity).
Имя метода | Назначение |
---|---|
showDialog(int, Bundle) | Запрос на отображение диалога согласно коду. Если диалог показывается впервые, то далее будет вызван метод onCreateDialog(int, Bundle), а затем onPrepareDialog(int, Bundle). Если диалог показывает второй или более раз (и при это для него ны вызывали метод removeDialog(int)), то будет вызван только onPrepareDialog(int, Dialog, Bundle). |
onCreateDialog(int, Bundle) | В этом методе создается диалог согласно коду, далее всегда следует вызов метода onPrepareDialog(int, Bundle). Если диалог не удалялся принудительно методом removeDialog(int), то этот метод для одного и тоже диалога будет вызван только один раз за жизнь Activity. Из этого следует, что любую настройку диалога следует проводить в методе onPrepareDialog(int, Dialog, Bundle). |
onPrepareDialog(int, Dialog, Bundle) | Перед тем как отобразить диалог, система всегда вызывает этот метод. Если вам нужно задавать какие-то значение для диалога, которые могут меняться от показа к показу, то именно тут для этого самое место. |
dismissDialog(int) | Прячет диалог, но не уничтожает его. |
removeDialog(int) | Прячет диалог, если он был на экране, и уничтожает его. Если вы уверены, что больше этот диалог вам не понадобиться, то смело его удаляйте. |
Заметка: для первых 3 методов существуют аналогичные, но без аргумента Bunlde. В примерах кода мы будем больше использовать именно их, так как наши диалоги достаточно просты и не требуют дополнительной инициализации.
Владея всем этим арсеналом, приступим к делу.
DialogFactory — зачем и как?
Безусловно, мы могли бы создавать нужные нам диалоги прямо в методе onCreateDialog(), но давайте предположим, что нам понадобится такой же набор диалогов для другой Activity. Вместо того, чтобы заниматься копи-пастой, я предлагаю сразу сделать фабричный метод для диалогов. Внимание, код!
package by.idev.dialog;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.EditText;
import android.widget.Toast;
/**
* Утилитарный класс с фабричным методом
* для создания диалогов по коду
*
* @author dmitrykunin
*
*/
public class DialogFactory {
protected DialogFactory() {};
//Констатны, описывающие различные типы диалогов
public final static int DIALOG_ALERT = 0;
public final static int DIALOG_PROGRESS = 1;
public final static int DIALOG_INPUT = 2;
/**
* Фабричный метод возращающий
* диалог по его коду
*
* @param id код диалога
* @param context
* @return диалог, соответсвующий коду
*/
public static Dialog getDialogById(int id, final Context context) {
Dialog dialog = null;
switch (id) {
case DIALOG_ALERT:
dialog = createAlertDialog(context);
break;
case DIALOG_PROGRESS:
dialog = createProgressDialog(context);
break;
case DIALOG_INPUT:
dialog = createInputAlert(context);
break;
}
return dialog;
}
}
Теперь рассмотрим по очереди создание AlertDialog, содержащего ListView (метод createAlertDialog()), ProgressDialog в простейшем виде ( метод createProgressDialog()), и AlertDialog c текстовым полем ввода (метод createInputDialog()).
AlertDialog со списком значений
Для начала проиллюстрирую, что мы получим в итоге.
Диалог со списком. При нажатии на элемент списка диалог исчезает и на экране появляется тост, с указанием, какой элемент был выбран.
private static Dialog createAlertDialog(final Context context) {
Dialog dialog;
Builder builder = new AlertDialog.Builder(context);
//В этом диалоге будет список доменов,
//по клику на один из которых отработает событие
final String[] domens = {"idev.by", "google.com", "apple.com"};
DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogArg, int which) {
Toast.makeText(context, "Button clicked: "+which, 1000).show();
dialogArg.dismiss();
}
};
DialogInterface.OnClickListener onItemClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogArg, int which) {
Toast.makeText(context, "Item clicked: "+domens[which], 1000).show();
dialogArg.dismiss();
}
};
//Пример работы с Builder, удобная инициализация диалога
dialog = builder.setTitle("Alert dialog")
.setPositiveButton("Positive", onClickListener)
.setNeutralButton("Neutral", onClickListener)
.setNegativeButton("Negative", onClickListener)
.setItems(domens, onItemClickListener).create();
return dialog;
}
Обратите внимание, как при помощи Builder очень быстро проходит инициализация диалога, ее можно выполнить буквально в одну строку =). Вид списка можно настраивать на свой вкус, но не будем на это отвлекаться.
ProgressDialog
В нашем случае будет иметь вид:
private static Dialog createProgressDialog(final Context context) {
ProgressDialog dialog;
dialog = new ProgressDialog(context);
dialog.setMessage("Please wait");
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Dismiss", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
return dialog;
}
Все довольно просто.
AlertDialog с тектовым полем
Делать нечто подобное приходится довольно часто, например, если нужно спросить что-то у пользователя.
После ввода текста и нажатия "ОК" на экране появится тост с введенным текстом.
private static Dialog createInputAlert(final Context context) {
Dialog dialog;
Builder builder = new Builder(context);
//Создадим текстовое поле для ввода
final EditText editText = new EditText(context);
DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String input = editText.getText().toString();
Toast.makeText(context, "Input was: "+input, 1000).show();
dialog.dismiss();
}
};
dialog = builder.setTitle("Input Alert")
.setMessage("Please enter something")
.setPositiveButton("Ok", onClickListener)
.setView(editText).create();
return dialog;
}
Ну вот мы наколбасили диалогов, а посмотреть на них не можем. Так что давай-те перейдем к описанию Activity, которая всем покажет.. наши диалоги =)
Работа с диалогами при помощи Activity
Суммарное количество кода тут не велико, за счет помощи со стороны SDK, нам не нужно реализовывать восстановление диалогов при поворотах экрана и заниматься прочими «веселыми» делами.
package by.idev.dialog;
import java.util.Date;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
public class ConstructiveDialogActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
Date currentTime = new Date();
dialog.setTitle("Showned at: "+currentTime.toLocaleString());
}
@Override
protected Dialog onCreateDialog(int id) {
return DialogFactory.getDialogById(id, this);
}
/**
* Вызывается по нажатию на кнопку,
* после чего в зависимости от нажатой
* кнопки покажет нужный диалог
*
* @param view
*/
public void onButtonClicked(View view) {
int buttonid = view.getId();
int dialogId = 0;
switch (buttonid) {
case R.id.alert_dlg:
dialogId = DialogFactory.DIALOG_ALERT;
break;
case R.id.input_dlg:
dialogId = DialogFactory.DIALOG_INPUT;
break;
case R.id.progress_dlg:
dialogId = DialogFactory.DIALOG_PROGRESS;
break;
}
showDialog(dialogId);
}
}
В методе onPrepareDialog() я сделал смену заголовка диалога, чтобы сделать более наглядным его вызов. Как видите, метод onCreateDialog() очень сократился за счет переноса всей логики в фабричный метод. Красиво. Мне нравится =)
Конечно картина не будет полной, если я не опишу Layout:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:stretchColumns="0,1,2">
<TextView
android:textStyle="bold"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center"
android:text="Нажми кнопку и получи диалог в подарок!"/>
<TableRow
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:padding="10dp">
<Button
android:id="@+id/alert_dlg"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Alert"
android:onClick="onButtonClicked"/>
<Button
android:id="@+id/progress_dlg"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Progress"
android:onClick="onButtonClicked"/>
<Button
android:id="@+id/input_dlg"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Input"
android:onClick="onButtonClicked"/>
</TableRow>
</TableLayout>
Ну а «общая картина» будет такой:
Краткое заключение
Мы научились создавать 3 типа диалогов, передавать управление ими в Activity и тем самым сокращать себе работу.
Исходники: ConstructiveDialogI.
Буду рад отзывам и комментариям!
Happy Coding! =)
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: