Kotlin Android Fundamentals 10.3: Projektowanie dla wszystkich

Ten moduł Codelab jest częścią kursu Android Kotlin Fundamentals. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności. Wszystkie ćwiczenia z tego kursu znajdziesz na stronie docelowej kursu Android Kotlin Fundamentals.

Wprowadzenie

Niezależnie od tego, czy tworzysz aplikację dla przyjemności, czy w celach biznesowych, warto zadbać o to, aby była ona użyteczna dla jak największej liczby użytkowników. Osiągnięcie tego celu ma wiele aspektów.

  • Obsługa języków RTL W językach europejskich i wielu innych tekst czyta się od lewej do prawej, a aplikacje pochodzące z tych regionów są zwykle zaprojektowane tak, aby dobrze pasowały do tych języków. Wiele innych języków, którymi posługuje się duża liczba osób, czyta się od prawej do lewej, np. arabski. Zadbaj o to, aby Twoja aplikacja działała w językach zapisywanych od prawej do lewej, aby zwiększyć liczbę potencjalnych odbiorców.
  • Skanowanie pod kątem ułatwień dostępu Próba zgadnięcia, jak inni użytkownicy mogą korzystać z Twojej aplikacji, wiąże się z pewnymi pułapkami. Aplikacja Accessibility Scanner analizuje aplikację i wskazuje miejsca, w których można poprawić ułatwienia dostępu.
  • Projektuj z myślą o TalkBack, dodając opisy treści. Wady wzroku są bardziej powszechne, niż mogłoby się wydawać, a wielu użytkowników, nie tylko osoby niewidome, korzysta z czytnika ekranu. Opisy treści to frazy, które czytnik ekranu odczytuje, gdy użytkownik wchodzi w interakcję z elementem ekranu.
  • Obsługa trybu nocnego Wielu użytkowników niedowidzących może poprawić kontrast, zmieniając kolory ekranu, co ułatwi im korzystanie z aplikacji. Android ułatwia obsługę trybu nocnego, dlatego zawsze warto go włączyć, aby zapewnić użytkownikom prostą alternatywę dla domyślnych kolorów ekranu.

W tym laboratorium kodowania poznasz każdą z tych opcji i dodasz jej obsługę do aplikacji GDG Finder.

Dowiesz się też, jak używać elementów w aplikacji na Androida. Możesz ich używać, aby uatrakcyjnić aplikację, zachowując przy tym jej dostępność.

Co warto wiedzieć

Musisz znać:

  • Jak tworzyć aplikacje z aktywnościami i fragmentami oraz jak poruszać się między fragmentami, przekazując dane.
  • Używanie widoków i grup widoków do tworzenia interfejsu, w szczególności RecyclerView.
  • Jak używać komponentów architektury, w tym ViewModel, z zalecaną architekturą do tworzenia dobrze zorganizowanych i wydajnych aplikacji.
  • Wiązanie danych, współprogramy i obsługa kliknięć myszą.
  • Jak połączyć się z internetem i lokalnie buforować dane za pomocą bazy danych Room.
  • Jak ustawiać właściwości widoku oraz jak wyodrębniać zasoby do plików zasobów XML i z nich korzystać.
  • Jak używać stylów i motywów do dostosowywania wyglądu aplikacji.
  • Jak korzystać z komponentów Material, zasobów wymiarów i niestandardowego kolorowania.

Czego się nauczysz

  • Jak sprawić, by z Twojej aplikacji mogło korzystać jak najwięcej osób.
  • Jak dostosować aplikację do języków zapisywanych od prawej do lewej.
  • Jak ocenić ułatwienia dostępu w aplikacji.
  • Jak używać opisów treści, aby aplikacja lepiej współpracowała z czytnikami ekranu.
  • Jak korzystać z elementów.
  • Jak dostosować aplikację do trybu ciemnego.

Jakie zadania wykonasz

  • Oceniaj i rozszerzaj daną aplikację, aby zwiększyć jej dostępność, dostosowując ją do języków zapisywanych od prawej do lewej.
  • Skanuj aplikację, aby określić, gdzie można poprawić ułatwienia dostępu.
  • Używaj opisów treści w przypadku obrazów.
  • Dowiedz się, jak korzystać z elementów rysowalnych.
  • Dodaj do aplikacji możliwość korzystania z trybu nocnego.

Aplikacja startowa GDG-finder wykorzystuje wszystko, czego do tej pory nauczyłeś się w tym kursie.

Aplikacja używa ConstraintLayout do wyświetlania 3 ekranów. Dwa z nich to tylko pliki układu, które posłużą Ci do poznania kolorów i tekstu na Androidzie.

Trzeci ekran to wyszukiwarka GDG. GDG, czyli Google Developer Groups, to społeczności deweloperów, które koncentrują się na technologiach Google, w tym na Androidzie. Grupy GDG na całym świecie organizują spotkania, konferencje, maratony szkoleniowe i inne wydarzenia.

Podczas tworzenia tej aplikacji pracujesz nad prawdziwą listą GDG. Ekran wyszukiwarki korzysta z lokalizacji urządzenia, aby sortować GDG według odległości.

Jeśli masz szczęście i w Twoim regionie działa GDG, możesz odwiedzić stronę internetową tej grupy i zarejestrować się na jej wydarzenia. Wydarzenia GDG to świetny sposób na poznanie innych deweloperów Androida i nauczenie się sprawdzonych metod, które nie zmieściły się w tym kursie.

Zrzuty ekranu poniżej pokazują, jak aplikacja będzie się zmieniać od początku do końca tego ćwiczenia.

Główna różnica między językami zapisanymi od lewej do prawej (LTR) a językami zapisanymi od prawej do lewej (RTL) polega na kierunku wyświetlania treści. Gdy kierunek interfejsu użytkownika zmieni się z od lewej do prawej na od prawej do lewej (lub odwrotnie), często nazywa się to powielaniem. Odbicie lustrzane obejmuje większość ekranu, w tym tekst, ikony pól tekstowych, układy i ikony z kierunkami (np. strzałki). Inne elementy nie są odzwierciedlane, np. liczby (zegar, numery telefonów), ikony, które nie mają kierunku (tryb samolotowy, Wi-Fi), elementy sterujące odtwarzaniem oraz większość wykresów.

Języki, w których tekst jest pisany od prawej do lewej, są używane przez ponad miliard osób na całym świecie. Deweloperzy Androida są na całym świecie, więc aplikacja GDG Finder musi obsługiwać języki pisane od prawej do lewej.

Krok 1. Dodaj obsługę języków pisanych od prawej do lewej

W tym kroku sprawisz, że aplikacja GDG Finder będzie działać w językach zapisywanych od prawej do lewej.

  1. Pobierz i uruchom aplikację GDGFinderMaterial, która jest aplikacją początkową w tym ćwiczeniu, lub kontynuuj pracę z kodem końcowym z poprzedniego ćwiczenia.
  2. Otwórz plik Android Manifest.
  3. W sekcji <application> dodaj ten kod, aby określić, że aplikacja obsługuje pisanie od prawej do lewej.
<application
        ...
        android:supportsRtl="true">
  1. Otwórz plik activity_main.xml na karcie Projekt.
  2. W menu Język podglądu wybierz Podgląd od prawej do lewej. (Jeśli nie widzisz tego menu, rozszerz panel lub zamknij panel Atrybuty, aby go odkryć).

  1. W sekcji Podgląd zauważ, że nagłówek „Wyszukiwarka GDG” został przesunięty w prawo, a reszta ekranu pozostała w zasadzie bez zmian. Ogólnie ten ekran jest akceptowalny. Wyrównanie w widoku tekstowym jest teraz nieprawidłowe, ponieważ tekst jest wyrównany do lewej, a nie do prawej.

  1. Aby to zadziałało na urządzeniu, w Ustawieniach urządzenia lub emulatora w Opcjach programisty wybierz Wymuś układ od prawej do lewej. (Jeśli musisz włączyć Opcje programisty, znajdź Numer kompilacji i klikaj go, aż pojawi się komunikat informujący o tym, że jesteś programistą. Zależy to od urządzenia i wersji systemu Android).

  1. Uruchom aplikację i sprawdź na urządzeniu, czy ekran główny wygląda tak samo jak w podglądzie. Zwróć uwagę, że przycisk FAB został przeniesiony na lewą stronę, a menu z 3 kreskami na prawą.
  2. W aplikacji otwórz panel nawigacji i przejdź do ekranu Szukaj. Jak widać poniżej, ikony nadal znajdują się po lewej stronie i nie widać żadnego tekstu. Okazuje się, że tekst znajduje się poza ekranem, po lewej stronie ikony. Jest to spowodowane tym, że kod używa odniesień do lewej i prawej strony ekranu we właściwościach widoku i ograniczeniach układu.

Krok 2. Zamiast lewej i prawej używaj początku i końca

„Lewa” i „prawa” strona ekranu (gdy patrzysz na ekran) nie zmieniają się, nawet jeśli kierunek tekstu ulegnie zmianie. Na przykład layout_constraintLeft_toLeftOf zawsze ogranicza lewą stronę elementu do lewej strony ekranu. W przypadku Twojej aplikacji tekst w językach zapisywanych od prawej do lewej jest poza ekranem, jak widać na zrzucie ekranu powyżej.

Aby to naprawić, zamiast „lewy” i „prawy” używaj terminologii StartEnd. Ta terminologia określa początek i koniec tekstu odpowiednio do kierunku tekstu w bieżącym języku, dzięki czemu marginesy i układy znajdują się we właściwych obszarach ekranów.

  1. Open list_item.xml
  2. Zastąp wszystkie odwołania do LeftRight odwołaniami do StartEnd.
app:layout_constraintStart_toStartOf="parent"

app:layout_constraintStart_toEndOf="@+id/gdg_image"
app:layout_constraintEnd_toEndOf="parent"
  1. Zastąp layout_marginLeft użytkownika ImageView tekstem layout_marginStart. Spowoduje to przesunięcie marginesu w odpowiednie miejsce, aby odsunąć ikonę od krawędzi ekranu.
<ImageView
android:layout_marginStart="
?
  1. Otwórz pokój fragment_gdg_list.xml. Sprawdź listę GDG w panelu Podgląd. Zwróć uwagę, że ikona nadal jest skierowana w niewłaściwym kierunku, ponieważ jest odwrócona (jeśli ikona nie jest odwrócona, upewnij się, że nadal wyświetlasz podgląd od prawej do lewej). Zgodnie z wytycznymi Material Design ikony nie powinny być odwracane.
  2. Otwórz plik res/drawable/ic_gdg.xml.
  3. W pierwszym wierszu kodu XML znajdź i usuń znak android:autoMirrored="true", aby wyłączyć dublowanie.
  4. Sprawdź podgląd lub ponownie uruchom aplikację i otwórz ekran wyszukiwania GDG. Układ powinien być teraz prawidłowy.

Krok 3. Pozwól Androidowi Studio wykonać pracę za Ciebie

W poprzednim ćwiczeniu wykonaliśmy pierwsze kroki w celu obsługi języków zapisywanych od prawej do lewej. Na szczęście Android Studio może przeskanować Twoją aplikację i skonfigurować wiele podstawowych elementów.

  1. W pliku list_item.xml w elemencie TextView zmień layout_marginStart z powrotem na layout_marginLeft, aby skaner miał coś do znalezienia.
<TextView
android:layout_marginLeft="@dimen/spacing_normal"
  1. W Android Studio wybierz Refactor > Add RTL support where possible (Refaktoryzacja > Dodaj obsługę języków pisanych od prawej do lewej, jeśli to możliwe) i zaznacz pola wyboru, aby zaktualizować plik manifestu i pliki układu, tak aby używały właściwości start i end.

  1. W panelu Podgląd refaktoryzacji znajdź folder app i rozwiń go, aby wyświetlić wszystkie szczegóły.
  2. W folderze aplikacji zauważ, że plik layout_marginLeft, który właśnie został zmieniony, jest wymieniony jako kod do refaktoryzacji.

  1. Zwróć uwagę, że w podglądzie są też wymienione pliki systemowe i pliki biblioteki. Kliknij prawym przyciskiem myszy foldery layoutlayout-watch-v20 oraz inne foldery, które nie należą do folderu app, i z menu kontekstowego wybierz Wyklucz.

  1. Przeprowadź refaktoryzację już teraz. (Jeśli pojawi się wyskakujące okienko dotyczące plików systemowych, upewnij się, że wykluczasz wszystkie foldery, które nie są częścią kodu aplikacji).
  1. Zwróć uwagę, że pole layout_marginLeft zostało zmienione z powrotem na layout_marginStart.

Krok 3. Przejrzyj foldery dla poszczególnych ustawień regionalnych

Do tej pory zmieniliśmy tylko kierunek domyślnego języka używanego w aplikacji. W przypadku aplikacji produkcyjnej wysyłasz plik strings.xml do tłumacza, aby przetłumaczył go na nowy język. W tym laboratorium kodowania aplikacja udostępnia plik strings.xml w języku hiszpańskim (do wygenerowania tłumaczeń użyliśmy Tłumacza Google, więc nie są one idealne).

  1. W Android Studio przełącz widok projektu na Pliki projektu.
  2. Rozwiń folder res. Zobaczysz foldery res/valuesres/values-es. Ciąg „es” w nazwie folderu to kod języka hiszpańskiego. Foldery values-"language code" zawierają wartości dla każdego obsługiwanego języka. Folder values bez rozszerzenia zawiera domyślne zasoby, które są stosowane w innych przypadkach.

  1. W folderze values-es otwórz plik strings.xml. Zobaczysz, że wszystkie ciągi znaków są w języku hiszpańskim.
  2. W Android Studio otwórz activity_main.xml na karcie Projekt.
  3. W menu Język podglądu wybierz Hiszpański. Tekst powinien być teraz w języku hiszpańskim.

  1. [Opcjonalnie] Jeśli dobrze znasz język zapisywany od prawej do lewej, utwórz folder values i plik strings.xml w tym języku i sprawdź, jak wyświetlają się na urządzeniu.
  2. [Opcjonalnie] Zmień ustawienia języka na urządzeniu i uruchom aplikację. Nie zmieniaj języka urządzenia na taki, którego nie znasz, ponieważ może to utrudnić cofnięcie zmian.

W poprzednim zadaniu ręcznie zmieniliśmy aplikację, a potem użyliśmy Android Studio, aby sprawdzić, czy można wprowadzić dodatkowe ulepszenia związane z obsługą języków pisanych od prawej do lewej.

Aplikacja Accessibility Scanner to najlepsze narzędzie, które pomoże Ci zadbać o dostępność aplikacji. Skanuje ona aplikację na urządzeniu docelowym i sugeruje ulepszenia, np. powiększenie obszarów dotyku, zwiększenie kontrastu i dodanie opisów obrazów, aby ułatwić korzystanie z aplikacji. Accessibility Scanner to aplikacja stworzona przez Google, którą możesz zainstalować ze Sklepu Play.

Krok 1. Zainstaluj i uruchom Accessibility Scanner

  1. Otwórz Sklep Play i w razie potrzeby zaloguj się. Możesz to zrobić na urządzeniu fizycznym lub w emulatorze. W tym laboratorium używamy emulatora.
  1. W Sklepie Play wyszukaj Accessibility Scanner od Google LLC. Upewnij się, że pobierasz właściwą aplikację wydaną przez Google, ponieważ skanowanie wymaga wielu uprawnień.

  1. Zainstaluj skaner na emulatorze.
  2. Po zainstalowaniu kliknij Otwórz.
  3. Kliknij Rozpocznij.
  4. Kliknij OK, aby rozpocząć konfigurację aplikacji Accessibility Scanner w Ustawieniach.

  1. Kliknij Accessibility Scanner, aby otworzyć ustawienia Ułatwienia dostępu na urządzeniu.

  1. Aby włączyć usługę, kliknij Użyj usługi.

  1. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie i przyznaj wszystkie uprawnienia.
  2. Następnie kliknij OK i wróć do ekranu głównego. Na ekranie może pojawić się niebieski przycisk z ikona potwierdzenia. Kliknięcie tego przycisku powoduje przetestowanie aplikacji na pierwszym planie. Możesz zmienić położenie przycisku, przeciągając go. Ten przycisk jest zawsze na wierzchu innych aplikacji, więc możesz w każdej chwili rozpocząć testowanie.

  1. Otwórz lub uruchom aplikację.
  2. Kliknij niebieski przycisk i zaakceptuj dodatkowe ostrzeżenia dotyczące bezpieczeństwa oraz uprawnienia.

Gdy po raz pierwszy klikniesz ikonę Skanera ułatwień dostępu, aplikacja poprosi o zezwolenie na dostęp do wszystkiego, co jest wyświetlane na ekranie. To uprawnienie może budzić obawy i tak jest w rzeczywistości.

Niemal nigdy nie należy przyznawać takich uprawnień, ponieważ umożliwiają one aplikacjom odczytywanie e-maili, a nawet pobieranie informacji o koncie bankowym. Aby jednak Accessibility Scanner mógł działać, musi sprawdzać aplikację w taki sam sposób jak użytkownik – dlatego potrzebuje tych uprawnień.

  1. Kliknij niebieski przycisk i poczekaj na zakończenie analizy. Zobaczysz ekran podobny do tego poniżej, z tytułem i przyciskiem FAB w czerwonej ramce. Oznacza to, że na tym ekranie są 2 sugestie dotyczące ułatwień dostępu.

  1. Kliknij pole otaczające GDG Finder. Otworzy się panel z dodatkowymi informacjami, jak pokazano poniżej, wskazujący problemy z kontrastem obrazu.
  2. Rozwiń informacje o kontraście obrazu, a narzędzie zaproponuje rozwiązania.
  3. Aby uzyskać informacje o kolejnym elemencie, kliknij strzałki po prawej stronie.

  1. W aplikacji otwórz ekran Zgłoś się do GDG i zeskanuj go za pomocą aplikacji Accessibility Scanner. Wyświetli ona kilka sugestii, jak pokazano poniżej po lewej stronie. Dokładnie 12. Niektóre z nich są duplikatami podobnych produktów.
  2. Kliknij ikonę „stos”  na dolnym pasku narzędzi, aby wyświetlić listę wszystkich sugestii, jak pokazano poniżej na zrzucie ekranu po prawej stronie. W tym laboratorium kodu zajmiemy się wszystkimi tymi problemami.

Pakiet ułatwień dostępu na Androida to zbiór aplikacji Google, które pomagają zwiększyć dostępność aplikacji. Obejmuje ona narzędzia takie jak TalkBack. TalkBack to czytnik ekranu, który zapewnia informacje zwrotne w postaci dźwięków, wibracji i komunikatów głosowych. Umożliwia użytkownikom poruszanie się po urządzeniach i korzystanie z treści bez patrzenia na ekran.

Okazuje się, że z TalkBack korzystają nie tylko osoby niewidome, ale też wiele osób z różnego rodzaju wadami wzroku. A nawet osoby, które po prostu chcą odpocząć od patrzenia na ekran.

Ułatwienia dostępu są więc dla wszystkich. W tym zadaniu wypróbujesz TalkBack i zaktualizujesz aplikację, aby dobrze z nią współpracowała.

Krok 1. Zainstaluj i uruchom pakiet Accessibility Suite

TalkBack jest wstępnie zainstalowany na wielu urządzeniach fizycznych, ale na emulatorze musisz go zainstalować.

  1. Otwórz Sklep Play.
  2. Znajdź pakiet ułatwień dostępu. Sprawdź, czy jest to właściwa aplikacja od Google.
  3. Jeśli nie jest zainstalowany, zainstaluj pakiet ułatwień dostępu.
  4. Aby włączyć TalkBack na urządzeniu, otwórz Ustawienia > Ułatwienia dostępu i włącz TalkBack, wybierając Użyj usługi. Podobnie jak skaner ułatwień dostępu, TalkBack wymaga uprawnień do odczytywania treści na ekranie. Gdy zaakceptujesz prośby o uprawnienia, TalkBack wyświetli listę samouczków, które pomogą Ci efektywnie korzystać z tej funkcji.
  5. Zatrzymaj się w tym miejscu i przejdź samouczki, choćby po to, aby dowiedzieć się, jak wyłączyć TalkBack, gdy skończysz.
  6. Aby zamknąć samouczek, kliknij przycisk Wstecz, a następnie kliknij dwukrotnie dowolne miejsce na ekranie.
  1. Dowiedz się, jak korzystać z aplikacji GDG Finder z TalkBack. Zwróć uwagę na miejsca, w których TalkBack nie podaje przydatnych informacji o ekranie lub elemencie sterującym. Naprawisz to w następnym ćwiczeniu.

Krok 2. Dodaj opis treści

Deskryptory treści to etykiety opisowe, które wyjaśniają znaczenie wyświetleń. Większość widoków powinna zawierać opisy treści.

  1. Uruchom aplikację GDG Finder i włącz TalkBack. Następnie przejdź do ekranu Zgłoś chęć prowadzenia GDG.
  2. Klikam obraz główny… i nic się nie dzieje.
  3. Otwórz plik add_gdg_fragment.xml.
  4. W polu ImageView dodaj atrybut deskryptora treści, jak pokazano poniżej. Ciąg stage_image_description jest dostępny w pliku strings.xml.
android:contentDescription="@string/stage_image_description"
  1. Uruchom aplikację.
  2. Kliknij obraz w sekcji Zgłoś chęć prowadzenia GDG. Powinien być teraz słyszalny krótki opis obrazu.
  3. [Opcjonalnie] Dodaj opisy treści do pozostałych obrazów w tej aplikacji. W aplikacji produkcyjnej wszystkie obrazy muszą mieć opisy treści.

Krok 3. Dodaj podpowiedzi do pól tekstowych z możliwością edycji

W przypadku elementów, które można edytować, np. EditText, możesz użyć elementu android:hint w pliku XML, aby pomóc użytkownikom w określeniu, co mają wpisać. Wskazówka jest zawsze widoczna w interfejsie, ponieważ jest domyślnym tekstem w polu wprowadzania.

  1. Nadal w pliku add_gdg_fragment.xml.
  2. Dodaj opisy i wskazówki dotyczące treści, korzystając z poniższego kodu jako przewodnika.

Dodaj do: textViewIntro

android:contentDescription="@string/add_gdg"

Dodaj do pól edycji tekstu odpowiednio:

android:hint="@string/your_name_label"

android:hint="@string/email_label"

android:hint="@string/city_label"

android:hint="@string/country_label"

android:hint="@string/region_label"
  1. Dodaj opis treści do labelTextWhy.
android:contentDescription="@string/motivation" 
  1. Dodaj podpowiedź do EditTextWhy. Po oznaczeniu pól edycji dodaj do etykiety opis treści, a także wskazówkę do pola.
android:hint="@string/enter_motivation"
  1. Dodaj opis treści przycisku przesyłania. Wszystkie przyciski muszą mieć opis tego, co się stanie po ich naciśnięciu.
android:contentDescription="@string/submit_button_description"
  1. Uruchom aplikację z włączoną funkcją TalkBack i wypełnij formularz, aby zgłosić się do prowadzenia GDG.

Krok 4. Utwórz grupę treści

W przypadku elementów interfejsu, które TalkBack powinien traktować jako grupę, możesz użyć grupowania treści. Powiązane treści, które są zgrupowane, są odczytywane razem. Użytkownicy technologii wspomagających nie będą musieli tak często przesuwać palcem po ekranie, skanować go ani czekać, aby odkryć wszystkie informacje na ekranie. Nie ma to wpływu na wygląd elementów sterujących na ekranie.

Aby zgrupować komponenty interfejsu, umieść je w elemencie ViewGroup, np. w elemencie LinearLayout. W aplikacji GDG Finder elementy labelTextWhyeditTextWhy doskonale nadają się do grupowania, ponieważ są ze sobą powiązane semantycznie.

  1. Otwórz plik add_gdg_fragment.xml.
  2. Umieść LinearLayout wokół LabelTextWhy i EditTextWhy, aby utworzyć grupę treści. Skopiuj i wklej poniższy kod. Ten LinearLayout zawiera już niektóre style, których potrzebujesz. (Upewnij się, że symbol button znajduje się POZA symbolem LinearLayout).
<LinearLayout android:id="@+id/contentGroup" android:layout_width="match_parent"
            android:layout_height="wrap_content" android:focusable="true"
            app:layout_constraintTop_toBottomOf="@id/EditTextRegion"
            android:orientation="vertical" app:layout_constraintStart_toStartOf="@+id/EditTextRegion"
            app:layout_constraintEnd_toEndOf="@+id/EditTextRegion"
            android:layout_marginTop="16dp" app:layout_constraintBottom_toTopOf="@+id/button"
            android:layout_marginBottom="8dp">

     <!-- label and edit text here –>

<LinearLayout/>
  1. Wybierz Code > Reformat code (Kod > Zmień format kodu), aby prawidłowo wciąć cały kod.
  2. Usuń wszystkie marginesy układu z urządzeń labelTextWhyeditTextWhy.
  3. W polu labelTextWhy zmień ograniczenie layout_constraintTop_toTopOf na contentGroup.
app:layout_constraintTop_toTopOf="@+id/contentGroup" />
  1. W polu editTextWhy zmień ograniczenie layout_constraintBottom_toBottomOf na contentGroup.
app:layout_constraintBottom_toBottomOf="@+id/contentGroup"
  1. Ogranicz EditTextRegionButton do contentGroup, aby usunąć błędy.
app:layout_constraintBottom_toTopOf="@+id/contentGroup"
  1. Dodaj marginesy do elementu LinearLayout. Opcjonalnie możesz wyodrębnić ten margines jako wymiar.
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"

Jeśli potrzebujesz pomocy, porównaj swój kod z add_gdg_fragment.xml w kodzie rozwiązania.

  1. Uruchom aplikację i przejdź do ekranu Zgłoś chęć prowadzenia GDG za pomocą TalkBack.

Krok 5. Dodaj region na żywo

Obecnie przycisk przesyłania ma etykietę OK. Lepiej, aby przycisk miał jedną etykietę i opis przed przesłaniem formularza, a po kliknięciu przez użytkownika i przesłaniu formularza dynamicznie zmieniał etykietę i opis treści. Możesz to zrobić za pomocą regionu na żywo.

Aktywny region informuje usługi ułatwień dostępu, czy użytkownik powinien być powiadamiany o zmianach widoku. Na przykład informowanie użytkownika o nieprawidłowym haśle lub błędzie sieci to świetny sposób na zwiększenie dostępności aplikacji. W tym przykładzie, aby uprościć sprawę, informujesz użytkownika, kiedy przycisk przesyłania zmienia stan.

  1. Otwórz plik add_gdg_fragment.xml.
  2. Zmień przypisanie tekstu przycisku na Prześlij, używając podanego zasobu ciągu znaków submit.
android:text="@string/submit"
  1. Dodaj do przycisku obszar aktywny, ustawiając atrybut android:accessibilityLiveRegion. Podczas wpisywania wartości masz do wyboru kilka opcji. W zależności od wagi zmiany możesz zdecydować, czy chcesz przerwać użytkownikowi pracę. W przypadku wartości „assertive” usługi ułatwień dostępu przerywają bieżącą mowę, aby natychmiast ogłosić zmiany w tym widoku. Jeśli ustawisz wartość „none”, żadne zmiany nie będą ogłaszane. Jeśli ustawisz wartość „polite”, usługi ułatwień dostępu będą ogłaszać zmiany, ale poczekają na swoją kolej. Ustaw wartość „polite”.

android:accessibilityLiveRegion="polite"
  1. W pakiecie add otwórz plik AddGdgFragment.kt.
  2. showSnackBarEvent Observer po zakończeniu wyświetlania SnackBar ustaw nowy opis treści i tekst przycisku.
binding.button.contentDescription=getString(R.string.submitted)
binding.button.text=getString(R.string.done)
  1. Uruchom aplikację i kliknij przycisk. Niestety przycisk i czcionka są za małe.

Krok 6. Popraw styl przycisku

  1. W pliku add_gdg_fragment.xml zmień wartości atrybutów widthheight przycisku na wrap_content, aby wyświetlała się pełna etykieta, a przycisk miał odpowiedni rozmiar.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
  1. Usuń atrybuty backgroundTint, textColortextSize z przycisku, aby aplikacja używała lepszego stylu motywu.
  2. Usuń atrybut textColor z textViewIntro. Kolory motywu powinny zapewniać dobry kontrast.
  3. Uruchom aplikację. Zwróć uwagę na znacznie bardziej użyteczny przycisk Prześlij. Kliknij Prześlij i zobacz, jak zmienia się na Gotowe.

Elementy to niewielkie elementy reprezentujące atrybut, tekst, podmiot lub działanie. Umożliwiają użytkownikom wprowadzanie informacji, wybieranie opcji, filtrowanie treści lub wywoływanie działania.

Chip to cienki widżet opakowujący ChipDrawable, który zawiera całą logikę układu i rysowania. Dodatkowa logika obsługuje nawigację za pomocą dotyku, myszy, klawiatury i ułatwień dostępu. Główny element i ikona zamknięcia są traktowane jako oddzielne logiczne widoki podrzędne i mają własne zachowanie nawigacyjne oraz stan.

Elementy korzystają z zasobów rysowalnych. Obiekty rysowalne w Androidzie umożliwiają rysowanie na ekranie obrazów, kształtów i animacji. Mogą mieć stały rozmiar lub być dynamicznie dopasowywane. Możesz używać obrazów jako elementów rysowalnych, np. obrazów w aplikacji GDG. Możesz też używać rysunków wektorowych, aby narysować wszystko, co tylko sobie wyobrazisz. Istnieje też obraz z możliwością zmiany rozmiaru, zwany obrazem 9-patch, który nie jest omawiany w tym ćwiczeniu z programowania. Logo GDG w pliku drawable/ic_gdg.xml to kolejny element rysowalny.

Obiekty rysowalne nie są widokami, więc nie można ich umieścić bezpośrednio w elemencie ConstraintLayout. Musisz umieścić je w elemencie ImageView. Możesz też używać zasobów rysowalnych jako tła widoku tekstu lub przycisku. Tło będzie rysowane za tekstem.

Krok 1. Dodaj elementy do listy GDG

Poniższy zaznaczony element używa 3 elementów rysowalnych. Tło i znacznik wyboru są rysunkami. Dotknięcie elementu powoduje efekt fali, który jest tworzony za pomocą specjalnego elementu RippleDrawable, który wyświetla efekt fali w odpowiedzi na zmiany stanu.

W tym zadaniu dodasz do listy GDG elementy, które będą zmieniać stan po wybraniu. W tym ćwiczeniu dodasz u góry ekranu Wyszukiwanie wiersz przycisków o nazwie chips. Każdy przycisk filtruje listę GDG, aby użytkownik otrzymywał tylko wyniki z wybranego regionu. Gdy przycisk zostanie wybrany, zmieni się jego tło i pojawi się na nim znacznik wyboru.

  1. Otwórz plik fragment_gdg_list.xml.
  2. Utwórz element com.google.android.material.chip.ChipGroup w elemencie HorizontalScrollView.. Ustaw jego właściwość singleLine na true, aby wszystkie elementy były ułożone w jednym wierszu z możliwością przewijania w poziomie. Ustaw właściwość singleSelection na true, aby w danej chwili można było wybrać tylko jeden element w grupie. Oto kod.
<com.google.android.material.chip.ChipGroup
    android:id="@+id/region_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:singleSelection="true"
    android:padding="@dimen/spacing_normal"/>
  1. W folderze layout utwórz nowy plik zasobu układu o nazwie region.xml, aby zdefiniować układ jednego elementu Chip.
  2. W pliku region.xml zastąp cały kod układem jednego Chip, jak podano poniżej. Zwróć uwagę, że Chip jest komponentem Material. Zwróć też uwagę, że znacznik wyboru pojawia się po ustawieniu właściwości app:checkedIconVisible. Pojawi się błąd dotyczący brakującego koloru selected_highlight.
<?xml version="1.0" encoding="utf-8"?>

<com.google.android.material.chip.Chip
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/Widget.MaterialComponents.Chip.Choice"
        app:chipBackgroundColor="@color/selected_highlight"
        app:checkedIconVisible="true"
        tools:checked="true"/>
  1. Aby utworzyć brakujący kolor selected_highlight, umieść kursor na kolorze selected_highlight, otwórz menu intencji i utwórz zasób koloru dla wybranego wyróżnienia. Opcje domyślne są odpowiednie, więc kliknij OK. Plik zostanie utworzony w folderze res/color.
  2. Otwórz plik res/color/selected_highlight.xml. Na tej liście stanów kolorów, zakodowanej jako <selector>, możesz podać różne kolory dla różnych stanów. Każdy stan i powiązany z nim kolor są zakodowane jako <item>. Więcej informacji o tych kolorach znajdziesz w artykule Motywy kolorystyczne.
  1. Wewnątrz <selector> dodaj do listy stanów element z domyślnym kolorem colorOnSurface. Na listach stanów ważne jest, aby zawsze uwzględniać wszystkie stany. Jednym ze sposobów na to jest ustawienie domyślnego koloru.
<item android:alpha="0.18" android:color="?attr/colorOnSurface"/>
  1. Nad domyślnym kolorem dodaj item w kolorze colorPrimaryVariant i ogranicz jego użycie do sytuacji, gdy wybrany stan to true. Listy stanów są przetwarzane od góry do dołu, podobnie jak instrukcja case. Jeśli żaden stan nie pasuje, stosowany jest stan domyślny.
<item android:color="?attr/colorPrimaryVariant"
         android:state_selected="true" />

Krok 2. Wyświetl wiersz z elementami

Aplikacja GDG tworzy listę elementów z regionami, w których działają grupy GDG. Gdy wybierzesz kartę, aplikacja przefiltruje wyniki, aby wyświetlać tylko wyniki GDG z danego regionu.

  1. W pakiecie search otwórz plik GdgListFragment.kt.
  2. onCreateView(), tuż nad instrukcją return, dodaj obserwatora w viewModel.regionList i zastąp onChanged(). Gdy lista regionów podana przez model widoku ulegnie zmianie, należy ponownie utworzyć komponenty. Dodaj instrukcję, aby natychmiast zwrócić wartość, jeśli podany argument data to null.
viewModel.regionList.observe(viewLifecycleOwner, object: Observer<List<String>> {
        override fun onChanged(data: List<String>?) {
             data ?: return
        }
})
  1. Wewnątrz onChanged(), poniżej testu wartości null, przypisz binding.regionList do nowej zmiennej o nazwie chipGroup, aby zapisać w pamięci podręcznej wartość regionList.
val chipGroup = binding.regionList
  1. Poniżej utwórz nowy layoutInflator do nadmuchiwania chipsów z chipGroup.context.
val inflator = LayoutInflater.from(chipGroup.context)
  1. Wyczyść i ponownie skompiluj projekt, aby pozbyć się błędu powiązania danych.

Pod inflatorem możesz teraz utworzyć rzeczywiste elementy, po jednym dla każdego regionu w regionList.

  1. Utwórz zmienną children, która będzie przechowywać wszystkie elementy. Przypisz do niego funkcję mapowania w przekazanym argumencie data, aby utworzyć i zwrócić każdy element.
val children = data.map {} 
  1. W funkcji lambda mapy dla każdego elementu regionName utwórz i rozwiń element. Gotowy kod znajdziesz poniżej.
val children = data.map {
   val children = data.map { regionName ->
       val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
       chip.text = regionName
       chip.tag = regionName
       // TODO: Click listener goes here.
       chip
   }
}
  1. W funkcji lambda, tuż przed zwróceniem wartości chip, dodaj detektor kliknięć. Gdy klikniesz chip, ustaw stan checked. Wywołaj funkcję onFilterChanged()viewModel, co spowoduje wywołanie sekwencji zdarzeń, które pobiorą wynik dla tego filtra.
chip.setOnCheckedChangeListener { button, isChecked ->
   viewModel.onFilterChanged(button.tag as String, isChecked)
}
  1. Na końcu lambdy usuń wszystkie bieżące widoki z chipGroup, a następnie dodaj wszystkie elementy z children do chipGroup. (Nie możesz zaktualizować elementów, więc musisz usunąć i ponownie utworzyć zawartość chipGroup).
chipGroup.removeAllViews()

for (chip in children) {
   chipGroup.addView(chip)
}

Ukończony obserwator powinien wyglądać tak:

   override fun onChanged(data: List<String>?) {
       data ?: return

       val chipGroup = binding.regionList
       val inflator = LayoutInflater.from(chipGroup.context)

       val children = data.map { regionName ->
           val chip = inflator.inflate(R.layout.region, chipGroup, false) as Chip
           chip.text = regionName
           chip.tag = regionName
           chip.setOnCheckedChangeListener { button, isChecked ->
               viewModel.onFilterChanged(button.tag as String, isChecked)
           }
           chip
       }
       chipGroup.removeAllViews()

       for (chip in children) {
           chipGroup.addView(chip)
       }
   }
})
  1. Uruchom aplikację i wyszukaj GDGS, aby otworzyć ekran Wyszukiwanie i użyć nowych elementów. Po kliknięciu każdego elementu aplikacja wyświetli poniżej grupy filtrów.

Tryb nocny umożliwia aplikacji zmianę kolorów na ciemny motyw, na przykład gdy w ustawieniach urządzenia włączono tryb nocny. W trybie nocnym aplikacje zmieniają domyślne jasne tło na ciemne i odpowiednio dostosowują wszystkie inne elementy ekranu.

Krok 1. Włącz tryb nocny

Aby udostępnić ciemny motyw aplikacji, zmień jej motyw z Light na DayNight. Motyw DayNight jest wyświetlany w jasnych lub ciemnych kolorach w zależności od trybu.

  1. styles.xml, zmień motyw nadrzędny AppThemeLight na DayNight.
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
  1. W metodzie MainActivityonCreate() wywołaj AppCompatDelegate.setDefaultNightMode(), aby programowo włączyć ciemny motyw.
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
  1. Uruchom aplikację i sprawdź, czy przełączyła się na ciemny motyw.

Krok 2. Wygeneruj własną paletę kolorów motywu ciemnego

Aby dostosować ciemny motyw, utwórz foldery z kwalifikatorem -night, którego będzie używać ciemny motyw. Możesz na przykład ustawić konkretne kolory w trybie nocnym, tworząc folder o nazwie values-night.

  1. Otwórz selektor kolorów na stronie material.io i utwórz paletę kolorów motywu nocnego. Możesz na przykład użyć ciemnoniebieskiego.
  2. Wygeneruj i pobierz plik colors.xml.
  3. Przełącz się na widok Pliki projektu, aby wyświetlić listę wszystkich folderów w projekcie.
  4. Znajdź folder res i go rozwiń.
  5. Utwórz folder zasobów res/values-night.
  6. Dodaj nowy plik colors.xml do folderu zasobów res/values-night.
  7. Uruchom aplikację z włączonym trybem nocnym. Powinna ona używać nowych kolorów zdefiniowanych w folderze res/values-night. Zwróć uwagę, że w elementach użyto nowego koloru dodatkowego.

Projekt Android Studio: GDGFinderFinal.

Obsługa języków RTL

  • W pliku manifestu Androida ustaw wartość android:supportsRtl="true".
  • Możesz wyświetlić podgląd tekstu zapisanego od prawej do lewej w emulatorze i sprawdzić układ ekranu w swoim języku. Na urządzeniu lub emulatorze otwórz Ustawienia, a w Opcjach programisty wybierz Wymuś układ od prawej do lewej.
  • Zastąp odwołania do LeftRight odwołaniami do StartEnd.
  • Wyłącz dublowanie elementów rysowalnych, usuwając android:autoMirrored="true".
  • Wybierz Refactor > Add RTL support where possible (Refaktoryzuj > Dodaj obsługę języków pisanych od prawej do lewej, jeśli to możliwe), aby Android Studio wykonało to za Ciebie.
  • Używaj folderów values-"language code" do przechowywania zasobów w określonym języku.

Skanowanie pod kątem ułatwień dostępu

Projektowanie z myślą o TalkBack z opisami treści

  • Zainstaluj Pakiet ułatwień dostępu na Androida od Google, który zawiera TalkBack.
  • Dodaj opisy treści do wszystkich elementów interfejsu. Na przykład:
    android:contentDescription="@string/stage_image_description"
  • W przypadku elementu, który można edytować, np. EditText, użyj atrybutu android:hint w pliku XML, aby podać użytkownikowi wskazówkę dotyczącą tego, co ma wpisać.
  • Twórz grupy treści, umieszczając powiązane elementy w grupie widoku.
  • Utwórz region na żywo, aby przekazywać użytkownikom dodatkowe informacje zwrotne za pomocą android:accessibilityLiveRegion.

Używanie elementów do implementowania filtra

  • Elementy to drobne elementy reprezentujące atrybut, tekst, encję lub działanie.
  • Aby utworzyć grupę elementów, użyj znaku com.google.android.material.chip.ChipGroup.
  • Określ układ dla 1 atrybutu com.google.android.material.chip.Chip.
  • Jeśli chcesz, aby elementy zmieniały kolor, podaj listę stanów kolorów jako <selector> z kolorami zależnymi od stanu:
    <item android:color="?attr/colorPrimaryVariant"
    android:state_selected="true" />
  • Powiąż elementy z danymi na żywo, dodając obserwatora do danych w modelu widoku.
  • Aby wyświetlić elementy, utwórz inflator dla grupy elementów:
    LayoutInflater.from(chipGroup.context)
  • Utwórz elementy, dodaj odbiornik kliknięć, który wywołuje żądane działanie, i dodaj elementy do grupy elementów.

Obsługa trybu ciemnego

  • Użyj DayNight AppTheme, aby obsługiwać tryb ciemny.
  • Tryb ciemny możesz ustawić programowo:
    AppCompatDelegate.setDefaultNightMode()
  • Utwórz folder zasobów res/values-night, aby udostępniać niestandardowe kolory i wartości dla trybu ciemnego.

Dokumentacja dla deweloperów aplikacji na Androida:

Inne zasoby:

W tej sekcji znajdziesz listę możliwych zadań domowych dla uczniów, którzy wykonują ten moduł w ramach kursu prowadzonego przez instruktora. Nauczyciel musi:

  • W razie potrzeby przypisz pracę domową.
  • Poinformuj uczniów, jak przesyłać projekty.
  • Oceń zadania domowe.

Instruktorzy mogą korzystać z tych sugestii w dowolnym zakresie i mogą zadawać inne zadania domowe, które uznają za odpowiednie.

Jeśli wykonujesz ten kurs samodzielnie, możesz użyć tych zadań domowych, aby sprawdzić swoją wiedzę.

Pytanie 1

Które z tych elementów są obowiązkowe w przypadku obsługi języków zapisywanych od prawej do lewej?

▢ Zastąp LeftRight we właściwościach wartościami StartEnd

▢ Przełącz na język zapisywany od prawej do lewej

▢ Upewnij się, że wszystkie ikony używają android:autoMirrored="true".

▢ Podaj opisy treści

Pytanie 2

Które z tych narzędzi ułatwień dostępu jest wbudowane w większość urządzeń z Androidem?

▢ TalkBack

▢ Accessibility Scanner

▢ W Android Studio kliknij Refactor > Add RTL support where possible (Refaktoryzacja > Dodaj obsługę języków pisanych od prawej do lewej, jeśli to możliwe).

▢ Lint

Pytanie 3

Które z tych stwierdzeń dotyczących chipsów nie jest prawdziwe?

▢ Wyświetlasz komponenty w ramach ChipGroup.

▢ Możesz podać listę stanów kolorów dla ChipGroup.

▢ Elementy to drobne elementy reprezentujące atrybut, działanie lub tekst do wpisania.

▢ Jeśli aplikacja korzysta z elementów interfejsu, musisz zawsze włączyć DarkTheme.

Pytanie 4

Który motyw zapewnia style dla trybu ciemnego i jasnego?

▢ DayNight

▢ DarkTheme

▢ DarkAndLightTheme

▢ Light

Pytanie 5

Czym jest region na żywo?

▢ Węzeł zawierający informacje ważne dla użytkownika

▢ Obszar ekranu, który zmienia kształt zgodnie z wytycznymi Material Design.

▢ Widok, który umożliwia przesyłanie strumieniowe wideo

▢ animowany obiekt rysowalny,