Загальна інформація
В деяких випадках потрібно показати діалогове вікно, де потрібно зробити який-небудь вибір або показати повідомлення про помилку. Безумовно, можна створити власне вікно, розташувати в ньому потрібні кнопки і обробляти їх натискання. Але, в Android вже є власні вбудовані діалогові вікна, які гнучко настроюються під задачі. Використання діалогових вікон для простих завдань дозволяє скоротити число класів Activity в додатку, економлячи ресурси пам'яті. Адже вам не доведеться реєструвати активність у маніфесті, думати над компонуванням елементів на екрані і так далі.
Діалогові вікна Android являють собою напівпрозорі «плаваючі» активності, що частково перекривають батьківський екран, з якого їх викликали. Як правило, вони затінюють батьківську активність позаду себе за допомогою фільтрів розмивання або затемнення. Ви можете встановити заголовок за допомоги методу setTitle() і вміст за допомогою методу setContentView().
Android підтримує наступні типи діалогових вікон:
Dialog - базовий клас для всіх типів діалогових вікон;
AlertDialog — діалогове вікно з кнопками, списком, прапорцями або перемикачами;
CharacterPickerDialog - діалогове вікно, що дозволяє вибрати символ з наголосом, пов'язаний з базовим символом;
ProgressDialog — діалогове вікно з індикатором прогресу за допомогою елемента ProgressBar;
DatePickerDialog — діалогове вікно вибору дати з елементом DatePicker;
TimePickerDialog — діалогове вікно вибору часу з елементом TimePicker.
Якщо ні один з існуючих типів діалогових вікон вам не підходить, то можна створити власне діалогове вікно.
Клас Dialog
Клас Dialog є базовим для всіх класів діалогових вікон. Оскільки ProgressDialog, TimePickerDialog і DatePickerDialog — розширення класу AlertDialog, вони також можуть мати командні кнопки.
Кожне діалогове вікно повинно бути визначено всередині активності, в якій буде використовуватися. Діалогове вікно можна відкрити один раз або кілька разів.
Для відображення діалогового вікна необхідно викликати метод showDialog() і передати йому в якості параметра ідентифікатор діалогу (константа, яку треба оголосити в коді програми), який ви хочете відобразити.
Метод dismissDialog() приховує діалогове вікно (але не усуває), не відображаючи його на екрані. Вікно залишається в пулі діалогових вікон даної активності. При повторному відображенні за допомогою методу showDialog() буде використана кешована версія вікна.
Метод removeDialog() видаляє діалогове вікно з пулу вікон даної активності. При повторному виклику методу showDialog() діалогове вікно доведеться створювати знову.
Розглянемо базовий приклад створення діалогового вікна на основі класу Dialog. Створіть найпростішу розмітку для діалогового вікна - текстове поле всередині LinearLayout. В розмітку головною активності додайте кнопку для виклику діалогового вікна. У коді для головної активності напишемо:
Dialog dialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R. layout.activity_main);
dialog = new Dialog(MainActivity.this);
// Встановіть заголовок
dialog.setTitle ("Заголовок діалогу");
// Передайте посилання на розмітку
dialog.setContentView(R. layout.dialog_view);
// Знайдіть елемент TextView всередині вашої розмітки
// і встановіть йому відповідний текст
TextView text = (TextView) dialog.findViewById(R. id.dialogTextView);
text.setText("Текст в діалоговому вікні. Ви любите котів?");
}
public void onClick(View v)
{
// Виводимо діалогове вікно на екран
dialog.show();
}
За замовчуванням при показі діалогового вікна головна активність затемнюється. В документації є константи, що дозволяють управляти ступенем затемнення:
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
lp.dimAmount = 0.6 f; // рівень затемнення від 1.0 до 0.0
dialog.getWindow().setAttributes(lp);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
// Встановіть заголовок
dialog.setTitle (Заголовок діалогу");
...
На емуляторі я не помітила різниці. У старій версії Android 2.3 був ще ефект розмиття WindowManager.LayoutParams.FLAG_BLUR_BEHIND, який тепер вважається застарілим. Якщо ви вперто все одно пропишите даний ефект, то отримаєте не ефект розмиття, а чорний фон. Хто знає, може вас влаштує такий варіант.
Методи onCreateDialog() і onPrepareDialog()
Метод onCreateDialog() викликається один раз при створенні вікна. Після початкового створення при кожному виклику методу showDialog() буде спрацьовувати обробник onPrepareDialog(). Якщо перевизначити цей метод, ви можете змінювати діалогове вікно при кожному його виведення на екран. Це дозволить привнести контекст у будь-який з відображуваних значень. Якщо потрібно перед кожним викликом діалогового вікна змінювати його властивості (наприклад, текстове повідомлення або кількість кнопок), то можна це реалізувати всередині цього методу. В цей метод передають ідентифікатор діалогу і сам об'єкт Dialog, який був створений в методі onCreateDialog().
@Override
public void onPrepareDialog(int id Dialog dialog) {
switch(id) {
case (TIME_DIALOG) :
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date currentTime = new Date(java.lang.System.currentTimeMillis());
String dateString = sdf.format(currentTime);
AlertDialog timeDialog = (AlertDialog)dialog;
timeDialog.setMessage(dateString);
break;
}
}
Так як в одному додатку може бути кілька діалогових вікон, то необхідно заздалегідь визначити діалогове вікно, яке буде використовуватися в активності. Для цього створюється ідентифікатор (константа з цілим числом). При виклику методу showDialog() ви передаєте цей ідентифікатор діалогового вікна в якості параметра. Після цього йде виклик методу onCreateDialog(), який повертає екземпляр потрібного діалогового вікна.
Можна створювати діалог без onCreateDialog(), наприклад в оброблювачі натискання кнопки виклику діалогу, але тоді він не буде приєднаний до поточної активності. Щоб прикріпити його до активності, необхідно викликати метод setOwnerActivity(), передавши йому як параметр поточну активність.
Перейдемо до прикладу. Якщо в активності повинні викликатися кілька різних діалогових вікон, спочатку необхідно визначити цілочисельний ідентифікатор кожного діалогу, наприклад:
static final int DIALOG_PAUSED_ID = 0;
static final int DIALOG_GAMEOVER_ID = 1;
Ці ідентифікатори потім можна використовувати у виклику методу showDialog() і в оброблювачі події onCreateDialog() в операторі switch:
protected Dialog onCreateDialog(int id) {
Dialog dialog;
switch(id) {
case DIALOG_PAUSED_ID:
// Код для роботи з діалогом Пауза
break;
case DIALOG_GAMEOVER_ID:
// Код для роботи з діалогом Гра закінчена
break;
default:
dialog = null;
}
return dialog;
}
Слід зазначити, що методи Activity.onCreateDialog() і Activity.onPrepareDialog() застаріли. Використовуйте DialogFragment.
AlertDialog з посиланням
Практичного сенсу можливо не має, але можна зробити текст повідомлення посиланням.
private void openSiteDialog() {
final SpannableString webaddress = new SpannableString(
"http://developer.alexanderklimov.ru/android/");
Linkify.addLinks(webaddress, Linkify.ALL);
final AlertDialog aboutDialog = new AlertDialog.Builder(
TestActivity.this).setMessage(webaddress)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).create();
aboutDialog.show();
((TextView) aboutDialog.findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance());
}
Створення власних діалогових вікон
У базовому прикладі на початку статті був показаний один спосіб створення власної розмітки для діалогового вікна. Також можна використовувати клас LayoutInflater, який дозволяє конвертувати XML розмітки відповідні об'єкти View у коді програми.
Спочатку необхідно ініціалізувати об'єкт LayoutInflater за допомогою виклику методу getLayoutInflater(), потім отримати кореневе подання методом inflate(int, ViewGroup), де перший параметр — ідентифікатор ресурсу схеми розміщення, другий — ідентифікатор кореневого подання розмітки:
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R. layout.custom_dialog,
(ViewGroup)findViewById(R. id.toast_layout));
Отримавши корінне подання, можна методом findViewById() ініціалізує всі дочірні подання в розмітці і задати для них потрібне наповнення. Наприклад, якщо в розмітці визначені віджети TextView і ImageView, код може виглядати так:
TextView text = (TextView)layout.findViewById(R. id.textView);
text.setText("Закрити? Ви впевнені?");
ImageView image = (ImageView)layout.findViewById(R. id.image);
image.setImageResource(R. drawable.icon);
Далі створюється об'єкт AlertDialog.Builder і методом setView() для нього встановлюється отримана раніше розмітка:
builder = new AlertDialog.Builder(this);
builder.setView(layout);
Інша ініціалізація властивостей діалогу та робота з ним в коді програми аналогічна роботі зі стандартним AlertDialog.