Warunki w Kotlinie – część 2

W tym ćwiczeniu dodasz kości do dotychczasowej aplikacji Dice Roller na Androida. Najpierw ukończ poprzednie ćwiczenia z programowania.

Zamiast pokazywać wartość rzutu kostką w aplikacji TextView, aplikacja wyświetli odpowiedni obraz kości do odsłoniętej strony. Aplikacja będzie o wiele lepsza i bardziej czytelna.

Otrzymasz link do pobrania kostek. Możesz je też dodać jako zasoby w aplikacji. Aby napisać kod, z którego użyjesz kości, użyjesz instrukcji when w Kotlinie.

Wymagania wstępne

  • Ukończ ćwiczenia z programowania Create the Roller Roller na Androida, które mają przycisk.
  • Możliwość zapisu instrukcji sterowania (if / else, when).
  • Możliwość aktualizowania interfejsu aplikacji na podstawie danych wejściowych użytkownika (modyfikowanie pliku MainActivity.kt).
  • Możliwość dodania detektora kliknięć do elementu Button.
  • Możliwość dodawania zasobów graficznych do aplikacji na Androida.

Czego się nauczysz

  • Jak zaktualizować ImageView, gdy aplikacja jest uruchomiona.
  • Jak dostosować działanie aplikacji w zależności od różnych warunków (za pomocą instrukcji when).

Co stworzysz

  • Aplikacja na rolkę z kółkiem na urządzeniu z atrybutem Button, aby rzucić kostką i zaktualizować obraz na ekranie.

Wymagania

  • Komputer z zainstalowaną aplikacją Android Studio.
  • Połączenie internetowe do pobierania zdjęć kości.

W tym zadaniu zastąpisz TextView układem ImageView, który wyświetla obraz wyniku rzutu kostką.

Otwórz aplikację Dice Roller

  1. Uruchom i uruchom aplikację Dice Roller w aplikacji Create Diroll Roller na Androida za pomocą przycisku w Android Studio.
    Aplikacja powinna wyglądać tak.

  1. Otwórz plik activity_main.xml (app > res > układ > activity_main.xml).
    Otworzy się edytor układu.

Usuwanie widoku tekstowego

  1. W Edytorze układu wybierz TextView w Drzewie komponentów.
    .
  1. Kliknij prawym przyciskiem myszy i wybierz Usuń lub naciśnij klawisz Delete.
  2. Na razie zignoruj ostrzeżenie widoczne na urządzeniu Button. W następnym kroku naprawisz to.

Dodawanie elementu ImageView w układzie

  1. Przeciągnij ikonę ImageView z palety do widoku Projekt, umieszczając ją nad Button.

  1. W oknie Wybierz zasób w sekcji Przykładowe dane kliknij awatar. Tego obrazu będziesz używać do czasu dodania kolejnych kości do następnego zadania.

  1. Naciśnij OK. Widok aplikacji powinien wyglądać tak: Projekt.

  1. W drzewie komponentów widać 2 błędy. Obiekt Button nie jest ograniczony w pionie, a ImageView nie ma takiego ograniczenia.

Button nie jest ograniczony w pionie, ponieważ usunięto element TextView, poniżej którego został pierwotnie umieszczony. Teraz musisz umieścić element ImageView i Button pod spodem.

Określanie położenia obrazu i przycisku

ImageView musi znaleźć się w pionie, niezależnie od tego, gdzie znajduje się obiekt Button.

  1. Dodaj ograniczenia poziome do obiektu ImageView. Połącz lewą stronę elementu ImageView z lewej krawędzi elementu nadrzędnego ConstraintLayout.
  2. Połącz prawą stronę elementu ImageView z prawą krawędzią obiektu nadrzędnego.
    Spowoduje to wyśrodkowanie obiektu ImageView w elemencie nadrzędnym.

  1. Dodaj ograniczenie pionowe do elementu ImageView, który łączy górną część obiektu ImageView z górną krawędzią elementu nadrzędnego.
    Element ImageView zostanie przesunięty do góry kolumny ConstraintLayout.
  2. Dodaj ograniczenie pionowe do elementu Button, który łączy górną część obiektu Button z dolną krawędzią obszaru ImageView.
    Element Button przesunie się w dół pod elementem ImageView.
  3. Ponownie wybierz ImageView i dodaj ograniczenie w pionie łączące dolną część ImageView na dole elementu nadrzędnego.
    Wyśrodkuje ImageView w pionie w ConstraintLayout.

Wszystkie ostrzeżenia o ograniczeniach powinny zostać usunięte.

W efekcie widok Projekt powinien wyglądać tak jak poniżej, ImageView z środkiem, a Button poniżej.

Na stronie ImageView w drzewie komponentów może pojawić się ostrzeżenie o dodaniu opisu treści do obiektu ImageView. Na razie nie martw się tym ostrzeżeniem, ponieważ później w ćwiczeniach z programowania skonfigurujesz opis treści dla ImageView na podstawie tego, który obraz kości widzisz. Ta zmiana zostanie dokonana w kotlinie.

W tym zadaniu pobierzesz zdjęcia kości i dodasz je do aplikacji.

Pobieranie kości

  1. Otwórz ten adres URL, by pobrać na komputer plik ZIP z kostkami. Zaczekaj na zakończenie pobierania.
  2. Znajdź plik na komputerze (prawdopodobnie jest to folder Pobrane).
  3. Aby rozpakować plik, kliknij go dwukrotnie. Spowoduje to utworzenie nowego folderu DiceImages z 6 plikami kości do wyświetlania liczb od 1 do 6.

Dodaj obrazy kości do aplikacji

  1. W Android Studio kliknij kolejno Wyświetl > Narzędzie Windows i Menedżer zasobów w menu lub kartę Menedżer zasobów po lewej stronie okna Projekt.
  2. Kliknij + poniżej Menedżera zasobów i wybierz Importuj obiekty rysowane. Otworzy się przeglądarka plików.

  1. Znajdź i wybierz 6 plików z kostkami. Możesz zaznaczyć pierwszy plik, a potem przytrzymać klawisz Shift, aby wybrać pozostałe pliki.
  2. Kliknij Otwórz.
  1. Kliknij Dalej, a następnie Importuj, aby potwierdzić, że chcesz zaimportować te 6 zasobów.

  1. Po zaimportowaniu plików 6 obrazów powinno pojawić się na liście aplikacji Do rysowania.

Dobra robota! W następnym zadaniu użyjesz tych obrazów w swojej aplikacji.

Ważne: – W będzie można odwoływać się do tych obrazów w kodzie Kotlin, podając ich identyfikatory zasobów:

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

Zastąp przykładowy awatar

  1. W edytorze projektów wybierz ImageView.
  2. W sekcji Atrybuty w sekcji Zadeklarowane atrybuty znajdź atrybut srcCompat ustawiony na zdjęcie awatara.

Pamiętaj, że atrybut srcCompat narzędzia wykorzystuje przesłany obraz tylko w widoku projektowania Androida Studio. Obraz będzie widoczny tylko dla deweloperów podczas tworzenia aplikacji, ale nie będzie widoczny podczas uruchamiania w emulatorze lub na urządzeniu.

  1. Kliknij mały awatar. Otworzy się okno dialogowe, w którym możesz wybrać nowy zasób do użycia z elementem ImageView.

  1. Wybierz element dice_1, który można rysować, i kliknij OK.

Wow! ImageView zajmuje cały ekran.

Następnie dostosujesz szerokość i wysokość obiektu ImageView, przez co obiekt Button nie zostanie ukryty.

  1. W oknie Atrybuty w sekcji Widżety ograniczeń znajdź atrybuty layout_width i layout_height. Obecnie ustawienie ma wartość wrap_content, co oznacza, że wartość ImageView jest równa wysokości elementu (obrazu źródłowego).
  2. Zamiast tego ustaw stałą szerokość 160 dp i stałą wysokość 200 dp na ImageView. Naciśnij Enter.

    Urządzenie ImageView jest teraz znacznie mniejsze.


Button może być trochę za blisko obrazu.

  1. Dodaj górny margines do przycisku o rozmiarze 16 dp, ustawiając go w widżecie ograniczeń.

Po zmianie widoku Projekt aplikacja wygląda znacznie lepiej.

Zmiana obrazu kości po kliknięciu przycisku

Układ został rozwiązany, ale musisz zaktualizować klasę MainActivity, by używała kości do gry.

W aplikacji MainActivity.kt występuje błąd. Jeśli spróbujesz uruchomić aplikację, zobaczysz ten błąd kompilacji:

Dzieje się tak, ponieważ Twój kod nadal odwołuje się do elementu TextView, który został usunięty z układu.

  1. Otwórz MainActivity.kt (app > java > com.example.diceroller > MainActivity.kt)

Kod odnosi się do elementu R.id.textView, ale Android Studio go nie rozpoznaje.

  1. W metodzie rollDice() wybierz kod, który odwołuje się do TextView, i go usuń.
// Update the TextView with the dice roll
val resultTextView: TextView = findViewByID(R.id.textView)
resultTextView.text = dice.roll().toString()
  1. W rollRice() utwórz nową zmienną o nazwie diceImage typu ImageView. Ustaw jego wartość na ImageView z układu. Użyj metody findViewById() i przekaż identyfikator zasobu ImageView, R.id.imageView jako argumentu wejściowego.
val diceImage: ImageView = findViewById(R.id.imageView)

Jeśli nie wiesz, jak znaleźć dokładny identyfikator zasobu ImageView, sprawdź identyfikator u góry okna Atrybuty.

Gdy odwołujesz się do tego identyfikatora zasobu w kotlinie, wpisz go dokładnie w ten sam sposób (małe litery i V, bez spacji). W przeciwnym razie w Android Studio pojawi się błąd.

  1. Dodaj ten wiersz kodu, aby przetestować, czy ImageView jest prawidłowo aktualizowany po kliknięciu przycisku. Gry z kośćmi nie zawsze są „2” – po prostu użyj obrazu dice_2 do testów.
diceImage.setImageResource(R.drawable.dice_2)

Ten kod wywołuje metodę setImageResource() w obiekcie ImageView, przekazując identyfikator zasobu obrazu dice_2. ImageView na ekranie zaktualizuje się i wyświetli obraz dice_2.

Metoda rollDice() powinna teraz wyglądać tak:

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. Uruchom aplikację, aby sprawdzić, czy działa bez błędów.

Aplikacja powinna zacząć od pustego ekranu z wyjątkiem przycisku Rolka.

Po kliknięciu przycisku pojawi się obraz kości z wartością 2. Tak!

Udało Ci się zmienić obraz na podstawie przycisku. Jesteś coraz bliżej celu

Niewątpliwie rzut kostką nie będzie zawsze remisem. Użyj mechanizmów zdobytych w ramach ćwiczenia Dodawanie warunkowych do różnych rzutów kostką, by odpowiednio dopasować kości do wyświetlenia na ekranie w zależności od losowej rzutu kostką.

Zanim zaczniesz pisać kod, zastanów się, jak powinna działać aplikacja, pisząc pseudokod, który opisuje, co powinno się stać. Przykład:

Jeśli użytkownik ma wartość 1, wyświetl obraz dice_1.

Jeśli użytkownik ma 2, wyświetl obraz dice_2.

itd.

Powyższy pseudokod może zostać zapisany w formie instrukcji if / else w Kotlinie na podstawie wartości rzutu kostką.

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

Jednak pisanie if / else każdego przypadku jest dość powtarzalne. Te same zasady można wyrazić w formie when. To bardziej zwięzłe (mniej kodu). Skorzystaj z tej metody w aplikacji.

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

Zaktualizuj metodę rollDice()

  1. W metodzie rollDice() usuń wiersz kodu, który za każdym razem ustawia identyfikator zasobu obrazu na dice_2.
diceImage.setImageResource(R.drawable.dice_2)
  1. Zastąp go instrukcją when, która aktualizuje element ImageView na podstawie wartości 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)
   }

Po wprowadzeniu zmian metoda rollDice() powinna wyglądać podobnie do tego.

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. Uruchom aplikację. Kliknięcie przycisku Rzuć powoduje zmianę obrazu kości poza inne niż 2. Udało się

Zoptymalizuj kod

Jeśli chcesz napisać jeszcze bardziej zwięzły kod, możesz wprowadzić zmianę w tym kodzie. Nie ma to wpływu na użytkowników aplikacji, ale sprawi, że kod będzie krótszy i mniej powtarzalny.

Zauważysz, że wywołanie diceImage.setImageResource() pojawia się w instrukcji wyciągu 6 razy.

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)
}

Zmieniają się jedynie identyfikatory używanych zasobów. Oznacza to, że możesz utworzyć zmienną do przechowywania identyfikatora zasobu. Następnie możesz wywołać diceImage.setImageResource()tylko raz w kodzie i przekazać prawidłowy identyfikator zasobu.

  1. Zastąp powyższy kod poniższym kodem.
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)

Nową koncepcją jest to, że wyrażenie when może zwracać wartość. W nowym fragmencie kodu wyrażenie when zwraca prawidłowy identyfikator zasobu, który zostanie zapisany w zmiennej drawableResource. Następnie za pomocą tej zmiennej możesz zaktualizować wyświetlony zasób graficzny.

  1. Zwróć uwagę na podkreślone na czerwono pole when. Gdy najedziesz na niego kursorem, zobaczysz komunikat o błędzie: 'Kiedy' wyrażenie musi być obszerne, dodaj wymagany oddział „&&33;in&&33; gałąź”.

Błąd wynika z tego, że wartość wyrażenia when jest przypisana do wartości drawableResource. Element when musi więc być kompletny – musi obsługiwać wszystkie możliwe przypadki, aby wartość była zawsze zwracana, nawet jeśli zmienisz kości na 12 boków. Android Studio zaleca dodanie gałęzi else. Możesz rozwiązać ten problem, zmieniając zgłoszenie gry 6 na else. Zgłoszenia od 1 do 5 są takie same, ale wszystkie pozostałe, w tym 6, są obsługiwane przez 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. Uruchom aplikację, aby upewnić się, że nadal działa prawidłowo. Sprawdź to na tyle, aby upewnić się, że wszystkie liczby są wyświetlane na obrazach od 1 do 6.

Ustawianie odpowiedniego opisu treści w elemencie ImageView

Po zastąpieniu numeru na grafice czytniki ekranu nie będą już wiedziały, która wartość została rzucona. Aby rozwiązać ten problem, zaktualizuj zasób graficzny ImageView. Opis treści powinien być tekstem, który wyświetla się w ImageView, aby czytniki ekranu mogły go opisać.

diceImage.contentDescription = diceRoll.toString()

Czytnik ekranu może odczytać ten opis zawartości, więc jeśli na ekranie wyświetli się obraz kostki "6", opis treści zostanie odczytany na głos tak jak w &&quot6.

Przydatniejsze uruchamianie

Gdy użytkownik otwiera aplikację po raz pierwszy, jest ona pusta (z wyjątkiem przycisku Rolka), co wygląda nietypowo. Użytkownicy mogą nie wiedzieć, czego mogą się spodziewać, dlatego po uruchomieniu aplikacji i utworzeniu funkcji Activity zmień interfejs, by wyświetlać losową kostkę. Użytkownicy z większym prawdopodobieństwem zrozumieją, że kliknięcie przycisku Rzuć spowoduje rzut kostką.

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()
}

Skomentuj kod

Dodaj kilka komentarzy do kodu, aby opisać, co się dzieje w napisanym kodzie.

Tak może wyglądać Twoja metoda 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()
}

Pełny plik MainActivity.kt znajdziesz w kodzie rozwiązań podanym na GitHubie, do którego link znajdziesz poniżej.

Super Ci poszło! Teraz możesz dodać tę aplikację do kolejnej nocy z przyjaciółmi!

Kod rozwiązania tego ćwiczenia z programowania znajdziesz w projekcie i module przedstawionym poniżej.

Aby pobrać kod z ćwiczenia z programowania na GitHubie i otworzyć go w Android Studio, wykonaj te czynności.

  1. Włącz Android Studio.
  2. W oknie Witamy w Android Studio kliknij Sprawdź projekt na podstawie kontroli wersji.
  3. Wybierz Git.

  1. W oknie Kopiowanie repozytorium wklej podany adres URL kodu w polu URL.
  2. Kliknij przycisk Przetestuj, poczekaj, aż pojawi się zielony dymek z informacją Połączenie uda się.
  3. Opcjonalnie zmień Katalog na inny niż sugerowane wartości domyślne.

  1. Kliknij Kopiuj. Android Studio zacznie pobierać kod.
  2. W wyskakującym okienku Kontrola wersji kliknij Tak.

  1. Poczekaj na otwarcie Android Studio.
  2. Wybierz odpowiedni moduł dla początków programowania lub kodu rozwiązania.

  1. Kliknij przycisk Uruchom , by utworzyć i uruchomić kod.
  • Użyj funkcji setImageResource(), aby zmienić obraz wyświetlany w elemencie ImageView.
  • Używaj instrukcji sterowania, na przykład wyrażeń if / else lub when do obsługi różnych przypadków w aplikacji, np. wyświetlania różnych obrazów w różnych okolicznościach.

Wykonaj te czynności:

  1. Dodaj kolejną kostkę do aplikacji, by jeden przycisk Rzut dał 2 wyniki. Ile elementów (ImageViews) będziesz potrzebować w układzie? Jak wpłynie to na kod MainActivity.kt?

Sprawdzanie zadań:

Gdy aplikacja będzie działać, powinna wyświetlić się bezbłędnie.