Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
На прошлом уроке мы практически полностью реализовали UI экрана. Сейчас обрабатываем несколько событий кликов, появилась динамика, но функционал тренажера ещё не реализован. В этой статье превратим заготовку в полноценный экран приложения для изучения английских слов. Здесь будет мало про сам Android — сначала нужно подготовить почву, чтобы наглядно показывать как всё работает на примере полноценного приложения.
На данный момент у нас есть метод onCreate и три дополнительных метода для изменения состояния кнопок. В данный момент мы меняем конкретные захардкоженные кнопки. Задача — сделать эти методы более универсальными, чтобы любую из четырёх кнопок можно было сделать корректной, некорректной или нейтральной. Для этого параметризуем функции: выносим прописанные view в параметры, чтобы методы принимали их и внутри применяли стилизацию.
Сначала добавим недостающие идентификаторы в разметке: добавим id к иконке закрытия и к 2-му и 4-му контейнерам.
Три текущих метода меняют и контейнер с вариантом ответа, и диалог с результатом. Декомпозируем это действие и вынесем отображение результата в отдельный метод. Его оформим чуть позже, а пока удалим лишние преобразования из существующих методов.
Посмотрим внимательно на методы — к каким view мы обращаемся внутри? Видно, что мы всегда меняем только 3 элемента. Это значит, что их можно передавать в методы как параметры и внутри обезличенно обращаться к ним.
Параметры методов будут такими:
layoutAnswer с типом LinearLayout — контейнер в макете;tvVariantNumber и tvVariantValue с типами TextView — для цифры варианта ответа и самого слова.Теперь внутри метода обращаемся не к элементам разметки через байндинг, а к входным параметрам. Таким образом конкретные значения вариантов ответа перестанут быть захардкоженными и метод станет универсальным — что в него передаём, то и помечаем как верный или неверный вариант. То же самое делаем для метода корректного ответа и затем для нейтрального. Циклы уже не нужны, код выглядит легче.
Обратим внимание на слушатели кликов — функции теперь ожидают параметры. Воспроизведём старое поведение:
Теперь нужен метод, показывающий корректность ответа в виде диалога внизу экрана. Добавим четвёртый метод showResultMessage() с одним параметром — Boolean значением isCorrect.
Внутри объявим переменные для цвета, иконки и текста сообщения, а инициализировать их будем в зависимости от переданного булева значения. Если передали true — инициализируем позитивными значениями: цвет через getColor(), нужную иконку и текст. Иначе — инициализируем противоположными.
Через блок with(binding) прописываем видимости кнопок и применяем объявленные переменные:
Теперь достаточно вызывать метод в нужный момент, передавая булево значение — будет отображаться соответствующий результат. В onClickListener() для правильного ответа вызываем метод с параметром true, для неправильного — с параметром false.
Для реализации бизнес-логики воспользуемся классом, созданным в рамках курсовой работы по написанию телеграм-бота на Kotlin. В нём реализована основная логика приложения: хранение слов в словаре и генерация вопросов. Благодаря разделению логики на классы — можно переиспользовать один из них и внедрить в приложение с минимальными модификациями.
Логика состоит из 3 классов.
Два data class:
Word — представляет слово с полями original (слово на английском), translate (перевод) и learned (флаг, было ли слово выучено).Question — представляет вопрос: список вариантов ответов variants и объект правильного ответа correctAnswer.Класс тренажера LearnWordsTrainer:
dictionary — список объектов Word. Сейчас слова хранятся в списке; в будущем хранилище будет заменено на базу данных или сетевое API.currentQuestion — хранит текущий вопрос для проверки ответа пользователя.getNextQuestion() — генерирует новый вопрос. Фильтрует словарь, получая notLearnedList. Если все слова выучены — возвращает null. Иначе выбирает случайные слова из невыученных (если их меньше 4 — добирает из выученных), выбирает правильный ответ и создаёт объект Question.checkAnswer(userAnswerIndex) — проверяет индекс выбранного ответа. Если совпадает с правильным — возвращает true и помечает слово как выученное (learned = true). Если нет — возвращает false.Если логика непонятна с первого раза — перепишите код и разберитесь, расставив точки остановки и запустив debug-режим для пошагового отслеживания.
Создаём экземпляр LearnWordsTrainer и сохраняем в переменную trainer. Затем создаём метод showNextQuestion(), принимающий экземпляр тренажера как параметр.
Логика метода:
Question? из getNextQuestion(). Если он равен null или количество вариантов меньше 4 — скрываем всё и задаём кнопке пропуска текст "Complete" (логику завершения обучения доработаем позже).isVisible не ломает процесс).TextView.Question.variants присваиваем каждому слово.Навешиваем 4 слушателя — по одному для каждого варианта ответа. Все они идентичны, отличаются только индексами. Разберём первый, остальные создаются по аналогии.
При клике на layoutAnswer1 коллбэк вызывает checkAnswer(0) — индекс 0 соответствует первому слову из списка вариантов, которое было присвоено этой view. Метод checkAnswer() сравнивает нажатое слово с правильным и возвращает Boolean:
true → вызываем markAnswerCorrect() для окраски ячейки в зелёный и showResultMessage(true);false → вызываем markAnswerWrong() и showResultMessage(false).Добавляем слушатель на btnContinue. По кнопке «Продолжить»:
showNextQuestion() для отображения следующего слова.По кнопке Skip вешаем слушатель кликов, при нажатии также вызываем showNextQuestion().
Приложение для изучения слов полностью функционально: логика тренажера интегрирована, UI корректно реагирует на действия пользователя. В следующих уроках будем рассматривать конкретные технологии Android, попутно улучшая функциональность приложения.