Продолжаем разработку нашего первого приложения на Андроид. На этом уроке займемся таким необходимым функционалом, как отображение диалоговых окон. Возможно вы видели уже в приложениях, когда некое окно появляется поверх существующего, при этом основное окно становится полупрозрачным, выглядит это как-то так:
Простые диалоговые окна обычно используются чтобы задать пользователю какой-то вопрос и предложить несколько вариантов ответа, тип “Да”, “Нет” и “Отмена”. По этому они и называются диалоговые, т.к. компьютер с пользователем вступает в диалог и ему для продолжения работы нужны со стороны пользователя какие-то действия и решения. В данном случае диалоговое окно будет сообщать пользователю, что игра закончена, ему удалось угадать число и можно начать новую игру. Однако, мы не будем ограничиваться стандартным механизмом диалоговых окон, а сделаем свое собственное. Такие элементы называются кастомизированными (от анг.слова Custom – собственный, пользовательский, настраиваемый), т.е. мы будем делать не просто вариант “Да-Нет”, а со своими кнопками и внешним видом.
Добавим внутрь нашего класса MainActivity следующий код:
DialogData dialogData;
public static class DialogData {
public AlertDialog.Builder alertDialogBuilder = null;
public AlertDialog alertDialog = null;
public TextView textViewButtonNewGame;
public Context context;
public static DialogData CreateDialog(Context context) {
DialogData dialogDataYesNo = new DialogData();
dialogDataYesNo.context = context;
View promptsViewYesNo = LayoutInflater.from(context).inflate(R.layout.dialog_endgame, null);
dialogDataYesNo.alertDialogBuilder = new AlertDialog.Builder(context);
dialogDataYesNo.alertDialogBuilder.setView(promptsViewYesNo);
dialogDataYesNo.textViewButtonNewGame = promptsViewYesNo.findViewById(R.id.buttonNewGame);
dialogDataYesNo.textViewButtonNewGame.setOnClickListener((View.OnClickListener) context);
dialogDataYesNo.alertDialogBuilder
.setCancelable(false).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
((MainActivity) context).dialogButtonNewGame();
}
});
dialogDataYesNo.alertDialog = dialogDataYesNo.alertDialogBuilder.create();
return dialogDataYesNo;
}
}
В результате получится, что один класс (DialogData) расположен внутри другого класса (MainActivity). Также объявим сразу же переменную класса MainActivity, которая будет хранить экземпляр класса DialogData:
DialogData dialogData;
Теперь нужно добавить новый layout (мы это уже делали), дайте ему аналогичное имя dialog_endgame:
Содержание его будет крайне простое, нужно просто разместить заголовок со словом “УГАДАЛ!” и кнопку для начало новой игры:
В метод onCreate не забудьте добавить создание экземпляра диалогового окна и его инициализацию, кстати, заметьте, если вы захотите менять текст элементов, то делать это нужно будет примерно так, т.к. экземпляр элемента объявлен не в основном классе MainActivity, а в классе DialogData:
В данном случае я просто меняю текст кнопки, хотя мог это сделать и в описании xml. Но из кода текст при необходимости можно менять динамически.
Теперь нужно разместить код отображения диалогового окна, если игрок угадал число (Toast который там был, уже не нужен):
И теперь остался последний штрих – обработать нажатие на кнопку “Ещё играть”. Добавьте этот метод куда-нибудь внутрь класса MainActivity, я разместил его сразу за классом DialogData, хотя можно было и более аккуратно – после всех методов:
Теперь давайте рассмотрим некоторые моменты прямо начиная с этого метода. Следующий код закрывает развернутое на экране диалоговое окно:
dialogData.alertDialog.cancel();
Тут надо отметить, что диалоговое окно может вообще открываться в двух режимах – закрываемое и незакрываемое. Этот режим мы выбрали тут:
Обычно, если пользователь ткнет пальцем по экрану мимо окна, то оно закроется, это получается, когда setCancelable(true), в ином случае, хоть пользовать затыкается по экрану, окно так и будет оставаться открытым, закрыть его можно будет только программным путём через код, либо принудительно завершить приложение. Нам нужно как раз сделать именно так, потому что если пользователь закроет без вызова метода dialogButtonNewGame то не будет ничего что начало бы новую игру. Пользователю останется только созерцать на результат предыдущей. Это нехорошо, вряд ли это не начнёт бесить даже самого выдержанного))). По этому нужно стремиться делать так, чтобы пользователю всё нравилось.
Ещё один момент касаемый обработки вызова нажатия кнопки диалогового окна. Начинает он отсюда:
Помните, как мы добавляли обработчик нажатия кнопок через имплементацию? Там мы указывали ключевое слово this и компилятор кидал вызов метода onClick в наш класс. Здесь мы делаем по другому. Переменной класса нет, по этому такой класс называется анонимным, а имплементация нужна в любом случае. Деть её некуда кроме как запихнуть прямо туда. Однако, управление нам нужно передать в основной класс каким-то образом, чтобы мы могли генерировать новый код игры, очистить список и т.п. По этому, если бы мы заранее не позаботились об этом при создании класса и не передали ему переменную context с указанием this на наш класс MainActivity, то сделать это было бы невозможным. Таким же образом, класс DialogData содержит context и “знает” куда передать. Тип можно было бы использовать и не Context, а объявить, например, MainActivity context, тогда бы приводить к типу ((MainActivity) context) не пришлось бы. Однако, это дело вкуса, и я стараюсь делать более универсальный метод и использовать Context там, где это возможно.
Задание по уроку:
1. Разберитесь самостоятельно как программным путем (не по кнопке возврат) завершить работу Активити. Добавьте в диалоговое окно ещё одну кнопку “Выйти из игры”
2. Сделайте так чтобы при первом окончании игры надпись первой кнопки была “Ещё играть!”, а при следующих текст был бы “Может сыграем ещё?!”.
3. Попробуйте сделать так чтобы кнопка “Выйти из игры” случайным образом выводила один из вариантов текста: “Выйти из игры”, “Покинуть игру”, “Хватит, больше не хочу играть”, “Сыграю ещё потом”
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Урок 8 Урок 10
El Vinto, 2023 (Copyright)