Условные операторы в Kotlin — часть 2

В этой кодовой лаборатории вы добавите изображения игральных костей в существующее Android-приложение Dice Roller. Обязательно сначала выполните предыдущую лабораторную работу по созданию основы приложения Dice Roller.

Вместо того, чтобы отображать значение броска игральной кости в TextView , ваше приложение будет отображать соответствующее изображение игральной кости для количества сторон, которые были брошены. Это будет гораздо более наглядным и улучшенным пользовательским интерфейсом для вашего приложения.

Вам будет предоставлена ​​ссылка для загрузки изображений игральных костей, и вы добавите их в качестве ресурсов в свое приложение. Чтобы написать код, для которого нужно использовать изображение кости, вы будете использовать оператор when в Kotlin.

Предпосылки

  • Вы завершили работу над приложением Create a Dice Roller для Android с лабораторией кода Button .
  • Умеет писать операторы управления потоком (операторы if / else , when ).
  • Возможность обновлять пользовательский интерфейс приложения на основе пользовательского ввода (изменение файла MainActivity.kt ).
  • Возможность добавить прослушиватель кликов к Button.
  • Возможность добавлять ресурсы изображения в приложение для Android.

Что вы узнаете

  • Как обновить ImageView во время работы приложения.
  • Как настроить поведение вашего приложения в зависимости от различных условий (используя оператор when ).

Что вы будете строить

  • Приложение Dice Roller для Android, в котором есть Button для броска костей и обновления изображения на экране.

Что вам нужно

  • Компьютер с установленной Android Studio.
  • Подключение к Интернету для загрузки изображений игральных костей.

В этой задаче вы замените TextView в своем макете на ImageView , который отображает изображение результата броска костей.

Откройте приложение Dice Roller

  1. Откройте и запустите приложение Dice Roller из Android-приложения Create a Dice Roller с кнопкой в ​​Android Studio.
    Приложение должно выглядеть так.

  1. Откройте Activity_main.xml ( app > res > layout > activity_main.xml activity_main.xml .
    Откроется Редактор макетов .

Удалить текстовое представление

  1. В редакторе компоновки выберите TextView в дереве компонентов .
  1. Щелкните правой кнопкой мыши и выберите « Удалить » или нажмите клавишу « Delete ».
  2. Пока игнорируйте предупреждение на Button . Вы исправите это на следующем шаге.

Добавьте ImageView в макет

  1. Перетащите ImageView из палитры в представление « Дизайн» , расположив его над Button .

  1. В диалоговом окне « Выберите ресурс » выберите аватары в разделе « Примеры данных ». Это временное изображение, которое вы будете использовать, пока не добавите изображения игральных костей в следующей задаче.

  1. Нажмите ОК . Представление « Дизайн » вашего приложения должно выглядеть следующим образом.

  1. В дереве компонентов вы заметите две ошибки. Button не ограничена по вертикали, а ImageView не ограничен ни по вертикали, ни по горизонтали.

Button не ограничена по вертикали, потому что вы удалили TextView , ниже которого она была изначально расположена. Теперь вам нужно расположить ImageView и Button под ним.

Разместите ImageView и кнопку

Вам нужно вертикально ImageView на экране, независимо от того, где находится Button .

  1. Добавьте горизонтальные ограничения в ImageView . Соедините левую сторону ImageView с левым краем родительского ConstraintLayout .
  2. Соедините правую сторону ImageView с правым краем родителя.
    Это горизонтально ImageView внутри родителя.

  1. Добавьте вертикальное ограничение в ImageView , соединяющее верхнюю часть ImageView с верхней частью родителя.
    ImageView будет скользить до верхней части ConstraintLayout .
  2. Добавьте вертикальное ограничение в Button , соединяющее верхнюю часть Button с нижней частью ImageView .
    Button будет скользить вверх под ImageView .
  3. Теперь снова выберите ImageView и добавьте ограничение по вертикали, соединяющее нижнюю часть ImageView с нижней частью родителя.
    Это центрирует ImageView вертикально в ConstraintLayout .

Все предупреждения об ограничениях теперь должны исчезнуть.

После всего этого представление « Дизайн» должно выглядеть так: ImageView в центре и Button чуть ниже.

Вы можете заметить предупреждение в ImageView в дереве компонентов , в котором говорится о добавлении описания содержимого в ваш ImageView . Не беспокойтесь об этом предупреждении на данный момент, потому что позже в лаборатории кода вы будете устанавливать описание содержимого ImageView на основе того, какое изображение кости вы отображаете. Это изменение будет внесено в код Kotlin.

В этой задаче вы загрузите несколько изображений игральных костей и добавите их в свое приложение.

Скачать изображения игральных костей

  1. Откройте этот URL -адрес, чтобы загрузить zip-файл с изображениями игральных костей на свой компьютер. Дождитесь завершения загрузки.
  2. Найдите файл на своем компьютере (скорее всего, в папке « Загрузки »).
  3. Дважды щелкните ZIP-файл, чтобы распаковать его. При этом создается новая папка DiceImages , содержащая 6 файлов изображений игральных костей, отображающих значения костей от 1 до 6.

Добавьте изображения игральных костей в свое приложение

  1. В Android Studio нажмите « Вид» > «Окна инструментов» > «Диспетчер ресурсов » в меню или щелкните вкладку « Диспетчер ресурсов » слева от окна « Проект» .
  2. Щелкните + под диспетчером ресурсов и выберите Import Drawables . Откроется файловый браузер.

  1. Найдите и выберите 6 файлов изображений игральных костей. Вы можете выбрать первый файл, затем, удерживая нажатой клавишу Shift , выбрать остальные файлы.
  2. Щелкните Открыть .
  1. Нажмите «Далее» , а затем «Импорт» , чтобы подтвердить, что вы хотите импортировать эти 6 ресурсов.

  1. Если файлы были успешно импортированы, 6 изображений должны появиться в списке Drawable для вашего приложения.

Хорошо сделано! В следующей задаче вы будете использовать эти изображения в своем приложении.

Важный! - Вы сможете ссылаться на эти изображения в коде Kotlin с их идентификаторами ресурсов:

  • R.drawable.dice_1
  • R.drawable.dice_2
  • R.drawable.dice_3
  • R.drawable.dice_4
  • R.drawable.dice_5
  • R.drawable.dice_6

Замените образец изображения аватара

  1. В редакторе дизайна выберите ImageView .
  2. В Attributes в разделе Declared Attributes найдите атрибут srcCompat инструмента, для которого задано изображение аватара.

Помните, что атрибут tools srcCompat использует предоставленное изображение только в представлении « Дизайн » Android Studio. Изображение отображается для разработчиков только во время создания приложения, но не будет видно, когда вы фактически запустите приложение в эмуляторе или на устройстве.

  1. Щелкните крошечный предварительный просмотр аватара. Откроется диалоговое окно для выбора нового ресурса, который будет использоваться для этого ImageView .

  1. Выберите dice_1 и нажмите OK .

Вау! ImageView занимает весь экран.

Далее вы отрегулируете ширину и высоту ImageView , чтобы он не скрывал Button .

  1. В окне Attributes в виджете Constraints найдите атрибуты layout_width и layout_height . В настоящее время для них установлено значение wrap_content , что означает, что ImageView будет такой же высоты и ширины, как содержимое (исходное изображение) внутри него.
  2. Вместо этого установите фиксированную ширину 160 dp и фиксированную высоту 200 dp для ImageView . Нажмите «Ввод ».

    Теперь ImageView намного меньше.


Вы можете обнаружить, что Button расположена слишком близко к изображению.

  1. Добавьте верхнее поле к кнопке 16dp, установив его в Constraint Widget .

После обновления представления « Дизайн» приложение выглядит намного лучше!

Изменение изображения кости при нажатии кнопки

Макет был исправлен, но класс MainActivity необходимо обновить, чтобы использовать изображения игральных костей.

В настоящее время в приложении есть ошибка в файле MainActivity.kt . Если вы попытаетесь запустить приложение, вы увидите эту ошибку сборки:

Это связано с тем, что ваш код все еще ссылается на TextView , который вы удалили из макета.

  1. Откройте MainActivity.kt ( приложение > java > com.example.diceroller > MainActivity.kt )

Код ссылается на R.id.textView , но Android Studio его не распознает.

  1. В rollDice() выберите любой код, ссылающийся на TextView , и удалите его.
// Update the TextView with the dice roll
val resultTextView: TextView = findViewByID(R.id.textView)
resultTextView.text = dice.roll().toString()
  1. По-прежнему внутри rollRice() создайте новую переменную с именем diceImage типа ImageView . Установите его равным ImageView из макета. Используйте метод findViewById() и передайте идентификатор ресурса для ImageView , R.id.imageView , в качестве входного аргумента.
val diceImage: ImageView = findViewById(R.id.imageView)

Если вам интересно, как определить точный идентификатор ресурса ImageView , проверьте идентификатор в верхней части окна атрибутов .

Когда вы ссылаетесь на этот идентификатор ресурса в коде Kotlin, убедитесь, что вы вводите его точно так же (строчная буква i, заглавная буква V, без пробелов). В противном случае Android Studio покажет ошибку.

  1. Добавьте эту строку кода, чтобы проверить правильность обновления ImageView при нажатии кнопки. Бросок кубика не всегда будет «2», просто используйте изображение dice_2 для целей тестирования.
diceImage.setImageResource(R.drawable.dice_2)

Этот код вызывает метод setImageResource() для ImageView , передавая идентификатор ресурса для изображения dice_2 . Это обновит ImageView на экране для отображения изображения dice_2 .

Теперь метод rollDice() должен выглядеть так:

private fun rollDice() {
    val dice = Dice(6)
    val diceRoll = dice.roll()
    val diceImage: ImageView = findViewById(R.id.imageView)
    diceImage.setImageResource(R.drawable.dice_2)
}
  1. Запустите приложение, чтобы убедиться, что оно работает без ошибок.

Приложение должно начинаться с пустого экрана, за исключением кнопки Roll .

После того, как вы нажмете кнопку, появится изображение кости, отображающее значение 2. Да!!

Вы смогли изменить изображение на основе нажатия кнопки! Вы приближаетесь!

Очевидно, что результатом игры в кости не всегда будет 2. Используйте логику потока управления, которую вы изучили в лаборатории кода « Добавление условного поведения для различных бросков костей», чтобы соответствующее изображение кости отображалось на экране в зависимости от случайного броска костей.

Прежде чем вы начнете вводить код, подумайте концептуально о том, как должно вести себя приложение, написав некоторый псевдокод , описывающий, что должно произойти. Например:

Если пользователь выбрасывает 1, отобразите изображение dice_1 .

Если пользователь выбрасывает 2, отобразите изображение dice_2 .

так далее...

Вышеупомянутый псевдокод может быть написан с операторами if / else в Kotlin на основе значения броска костей.

if (diceRoll == 1) {
   diceImage.setImageResource(R.drawable.dice_1)
} else if (diceRoll == 2) {
   diceImage.setImageResource(R.drawable.dice_2)
}
 ...

Однако написание if / else для каждого случая становится довольно повторяющимся. Та же самая логика может быть выражена более просто с оператором when . Это более лаконично (меньше кода)! Используйте этот подход в своем приложении.

when (diceRoll) {
   1 -> diceImage.setImageResource(R.drawable.dice_1)
   2 -> diceImage.setImageResource(R.drawable.dice_2)
   ...

Обновите метод rollDice()

  1. В rollDice() удалите строку кода, которая каждый раз устанавливает идентификатор ресурса изображения равным изображению dice_2 .
diceImage.setImageResource(R.drawable.dice_2)
  1. Замените его оператором when , который обновляет ImageView на основе значения diceRoll .
   when (diceRoll) {
       1 -> diceImage.setImageResource(R.drawable.dice_1)
       2 -> diceImage.setImageResource(R.drawable.dice_2)
       3 -> diceImage.setImageResource(R.drawable.dice_3)
       4 -> diceImage.setImageResource(R.drawable.dice_4)
       5 -> diceImage.setImageResource(R.drawable.dice_5)
       6 -> diceImage.setImageResource(R.drawable.dice_6)
   }

Метод rollDice() должен выглядеть так, когда вы закончите с изменениями.

private fun rollDice() {
   val dice = Dice(6)
   val diceRoll = dice.roll()

   val diceImage: ImageView = findViewById(R.id.imageView)

   when (diceRoll) {
       1 -> diceImage.setImageResource(R.drawable.dice_1)
       2 -> diceImage.setImageResource(R.drawable.dice_2)
       3 -> diceImage.setImageResource(R.drawable.dice_3)
       4 -> diceImage.setImageResource(R.drawable.dice_4)
       5 -> diceImage.setImageResource(R.drawable.dice_5)
       6 -> diceImage.setImageResource(R.drawable.dice_6)
   }
}
  1. Запустите приложение. Нажатие кнопки « Бросок » изменяет изображение кубика на другие значения, кроме 2. Это работает!

Оптимизируйте свой код

Если вы хотите написать еще более краткий код, вы можете внести следующее изменение кода. Это не оказывает никакого видимого влияния на пользователя вашего приложения, но сделает ваш код короче и менее повторяющимся.

Вы могли заметить, что вызов diceImage.setImageResource() появляется 6 раз в вашем операторе when.

when (diceRoll) {
    1 -> diceImage.setImageResource(R.drawable.dice_1)
    2 -> diceImage.setImageResource(R.drawable.dice_2)
    3 -> diceImage.setImageResource(R.drawable.dice_3)
    4 -> diceImage.setImageResource(R.drawable.dice_4)
    5 -> diceImage.setImageResource(R.drawable.dice_5)
    6 -> diceImage.setImageResource(R.drawable.dice_6)
}

Единственное, что меняется между каждым случаем, — это идентификатор используемого ресурса. Это означает, что вы можете создать переменную для хранения используемого идентификатора ресурса. Затем вы можете вызвать diceImage.setImageResource() только один раз в своем коде и передать правильный идентификатор ресурса.

  1. Замените приведенный выше код следующим.
val drawableResource = when (diceRoll) {
   1 -> R.drawable.dice_1
   2 -> R.drawable.dice_2
   3 -> R.drawable.dice_3
   4 -> R.drawable.dice_4
   5 -> R.drawable.dice_5
   6 -> R.drawable.dice_6
}

diceImage.setImageResource(drawableResource)

Новая концепция заключается в том, что выражение when может фактически возвращать значение. В этом новом фрагменте кода выражение when возвращает правильный идентификатор ресурса, который будет храниться в переменной drawableResource . Затем вы можете использовать эту переменную для обновления отображаемого ресурса изображения.

  1. Обратите внимание, что when теперь подчеркнуто красным. Если вы наведете на него указатель мыши, вы увидите сообщение об ошибке: «когда» выражение должно быть исчерпывающим, добавьте необходимую ветвь «иначе» .

Ошибка заключается в том, что значение выражения when присваивается drawableResource when поэтому оно должно быть исчерпывающим — оно должно обрабатывать все возможные случаи, чтобы всегда возвращалось значение, даже если вы переходите на 12-гранную игральную кость. Android Studio предлагает добавить ветку else . Вы можете исправить это, изменив регистр 6 на else . Случаи от 1 до 5 одинаковы, но все остальные, включая 6 , обрабатываются else .

val drawableResource = when (diceRoll) {
   1 -> R.drawable.dice_1
   2 -> R.drawable.dice_2
   3 -> R.drawable.dice_3
   4 -> R.drawable.dice_4
   5 -> R.drawable.dice_5
   else -> R.drawable.dice_6
}

diceImage.setImageResource(drawableResource)
  1. Запустите приложение, чтобы убедиться, что оно по-прежнему работает правильно. Обязательно протестируйте его достаточно, чтобы убедиться, что вы видите, что все числа появляются с изображениями игральных костей от 1 до 6.

Установите соответствующее описание содержимого в ImageView

Теперь, когда вы заменили выпавшее число изображением, средства чтения с экрана больше не могут определить, какое число выпало. Чтобы исправить это, после обновления ресурса изображения обновите описание содержимого ImageView . Описание содержимого должно быть текстовым описанием того, что показано в ImageView , чтобы средства чтения с экрана могли его описать.

diceImage.contentDescription = diceRoll.toString()

Программы чтения с экрана могут читать вслух это описание содержимого, поэтому, если на экране отображается изображение «6», описание содержимого будет прочитано вслух как «6».

Создайте более полезный опыт запуска

Когда пользователь открывает приложение в первый раз, оно пустое (кроме кнопки « Прокрутить »), что выглядит странно. Пользователи могут не знать, чего ожидать, поэтому измените пользовательский интерфейс, чтобы он отображал случайный бросок костей при первом запуске приложения и создании Activity . Тогда пользователи с большей вероятностью поймут, что нажатие кнопки « Бросок » вызовет бросок кубика.

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)

   val rollButton: Button = findViewById(R.id.button)
   rollButton.setOnClickListener { rollDice() }

   // Do a dice roll when the app starts
   rollDice()
}

Прокомментируйте свой код

Добавьте в свой код комментарии, чтобы описать, что происходит в написанном вами коде.

После внесения всех этих изменений ваш rollDice() может выглядеть так.

/**
* Roll the dice and update the screen with the result.
*/
private fun rollDice() {
   // Create new Dice object with 6 sides and roll the dice
   val dice = Dice(6)
   val diceRoll = dice.roll()

   // Find the ImageView in the layout
   val diceImage: ImageView = findViewById(R.id.imageView)

   // Determine which drawable resource ID to use based on the dice roll
   val drawableResource = when (diceRoll) {
       1 -> R.drawable.dice_1
       2 -> R.drawable.dice_2
       3 -> R.drawable.dice_3
       4 -> R.drawable.dice_4
       5 -> R.drawable.dice_5
       else -> R.drawable.dice_6
   }

   // Update the ImageView with the correct drawable resource ID
   diceImage.setImageResource(drawableResource)

   // Update the content description
   diceImage.contentDescription = diceRoll.toString()
}

Полный файл MainActivity.kt см. в коде решения на GitHub, указанном ниже.

Удачи в завершении приложения Dice Roller! Теперь вы можете принести это приложение на следующую игровую ночь с друзьями!

Код решения для этой кодовой лаборатории находится в проекте и модуле, показанных ниже.

Чтобы получить код для этой лаборатории кода с GitHub и открыть его в Android Studio, выполните следующие действия.

  1. Запустите Android-студию.
  2. В окне « Добро пожаловать в Android Studio » нажмите « Извлечь проект из системы контроля версий» .
  3. Выберите Гит .

  1. В диалоговом окне Clone Repository вставьте предоставленный URL-адрес кода в поле URL -адрес.
  2. Нажмите кнопку « Тест », подождите и убедитесь, что появилось зеленое всплывающее окно с надписью « Успешное подключение ».
  3. При желании измените каталог на что-то отличное от предложенного по умолчанию.

  1. Щелкните Клонировать . Android Studio начинает получать ваш код.
  2. Во всплывающем окне Checkout from Version Control нажмите Да .

  1. Подождите, пока откроется Android Studio.
  2. Выберите правильный модуль для своего стартового кода или кода решения.

  1. Нажмите кнопку « Выполнить» для создания и запуска вашего кода.
  • Используйте setImageResource() для изменения изображения, отображаемого в ImageView .
  • Используйте операторы потока управления, такие как выражения if / else или выражения when , для обработки разных случаев в вашем приложении, например, для отображения разных изображений в разных обстоятельствах.

Сделайте следующее:

  1. Добавьте еще один кубик в приложение, чтобы одна кнопка броска давала 2 результата. Сколько ImageViews вам понадобится в вашем макете? Как это повлияет на код MainActivity.kt ?

Проверьте свою работу:

Ваше готовое приложение должно работать без ошибок и показывать два кубика.