Przenoszenie interfejsu użytkownika do układów elastycznych

Aplikacje na Androida muszą obsługiwać stale rozwijający się ekosystem form czynników. Interfejs użytkownika aplikacji powinien być elastyczny, aby pasował do różnych rozmiarów ekranu, a także różnych orientacji i stanów urządzenia.

Interfejs responsywny opiera się na zasadach elastyczności i ciągłości.

Elastyczność odnosi się do układów, które optymalnie wykorzystują dostępną przestrzeń i dostosowują się do zmian w tej przestrzeni. Dostosowanie może przybierać różne formy: od po prostu zwiększenia rozmiaru pojedynczego widoku, przez zmianę jego położenia w celu ułatwienia dostępu, po wyświetlanie lub ukrywanie dodatkowych widoków.

Ciągłość oznacza płynne przejście z jednego rozmiaru okna na drugi. Użytkownik powinien mieć możliwość korzystania z aplikacji bez zakłóceń. Zmiana rozmiaru może wymagać zniszczenia i ponownego utworzenia całej hierarchii widoku, dlatego ważne jest, aby użytkownik nie stracił miejsca ani danych.

Czego warto unikać

Unikaj używania wartości sprzętowych do podejmowania decyzji dotyczących układu. Możesz mieć pokusę, by podejmować decyzje na podstawie wartości stałej, ale w wielu sytuacjach te wartości nie są przydatne do określenia przestrzeni, w której może działać interfejs użytkownika.

Aplikacje mogą zmieniać rozmiar okna, gdy są uruchamiane w trybie wielookiennym, obrazu w obrazie lub okna o dowolnym rozmiarze, np. w ChromeOS. Może być nawet więcej niż 1 ekran fizyczny, np. w przypadku składanego urządzenia lub urządzenia z wieloma ekranami. We wszystkich tych przypadkach fizyczny rozmiar ekranu nie ma znaczenia przy podejmowaniu decyzji o sposobie wyświetlania treści.

Wiele urządzeń z oknami aplikacji o różnych rozmiarach.
Rysunek 1. Rozmiary okna mogą różnić się od fizycznych wymiarów urządzenia lub wyświetlacza.

Z tego samego powodu nie blokuj orientacji ani proporcji aplikacji. Urządzenie może być w konkretnej orientacji, ale Twoja aplikacja może mieć inną orientację, która zależy wyłącznie od rozmiaru okna. Na przykład na tablecie w orientacji poziomej podczas korzystania z trybu wielu okien aplikacja może być w orientacji pionowej, ponieważ jest wyższa niż szersza.

Nie próbuj też ustalić, czy urządzenie jest telefonem czy tabletem. To, co kwalifikuje się jako tablet, jest nieco subiektywne: czy chodzi o określony rozmiar, format obrazu czy kombinację rozmiaru i formatu obrazu? W miarę pojawiania się nowych formatów te założenia mogą się zmieniać, a rozróżnienie traci na znaczeniu.

Zamiast stosować którekolwiek z poprzednich strategii, użyj punktów przełamania i klasyfikacji rozmiarów okien.

Punkty graniczne i klasy rozmiarów okna

Rzeczywisty obszar ekranu przypisany do aplikacji to okno aplikacji. Może ona zajmować cały ekran lub jego część, więc podczas podejmowania decyzji dotyczących ogólnego układu aplikacji kieruj się rozmiarem okna.

Podczas projektowania pod kątem różnych formatów znajdź wartości progowe, w których te decyzje ogólne rozgałęziają się na różne kierunki. W tym celu elastyczny układ siatki Material Design udostępnia punkty przecięcia dla szerokości i wysokości, co pozwala mapować nieprzetworzone rozmiary na oddzielne, ustandaryzowane grupy nazywane klasami rozmiarów okna. Ze względu na powszechność przewijania pionowego większość aplikacji zwraca uwagę głównie na klasy rozmiarów szerokości, więc można je zoptymalizować pod kątem wszystkich rozmiarów ekranu, uwzględniając tylko kilka punktów przecięcia. (więcej informacji o klasach rozmiarów okien znajdziesz w artykule Korzystanie z klas rozmiarów okien).

Trwałe elementy interfejsu

Wskazówki dotyczące układu w ramach Material Design określają obszary przeznaczone na paski aplikacji, nawigację i treści. Zwykle pierwsze 2 są to trwałe elementy interfejsu znajdujące się u podstawy hierarchii widoku (lub bardzo blisko niej). Pamiętaj, że „trwały” niekoniecznie oznacza, że widok jest zawsze widoczny, ale raczej, że pozostaje na miejscu, podczas gdy inne widoki treści mogą się przemieszczać lub zmieniać. Na przykład element nawigacji może znajdować się w przesuwanym panelu, który nie jest widoczny na ekranie, ale zawsze jest dostępny.

Elementy trwałe mogą być elastyczne i zazwyczaj zajmują całą szerokość lub całą wysokość okna, dlatego do ich umieszczania lepiej używać klas rozmiarów. Określa to miejsce na treści. W tym fragmencie kodu aktywność korzysta z dolnego paska na małych ekranach i z górnego paska aplikacji na większych ekranach. Kwalifikowane układy używają punktów przełamania szerokości, jak opisano wcześniej.

<!-- res/layout/main_activity.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- content view(s) -->

    <com.google.android.material.bottomappbar.BottomAppBar
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        ... />
</androidx.constraintlayout.widget.ConstraintLayout>


<!-- res/layout-w600dp/main_activity.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        ... />

    <!-- content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>

Treść

Po umieszczeniu stałych elementów interfejsu użyj pozostałej przestrzeni na treści, np. za pomocą NavHostFragment w grafu nawigacji aplikacji. Więcej informacji znajdziesz w artykule Nawigacja w interfejsach responsywnych.

Upewnij się, że wszystkie dane są dostępne dla różnych rozmiarów

Większość frameworków do tworzenia aplikacji korzysta obecnie z modelu danych, który jest oddzielony od komponentów Androida, które przyczyniają się do tworzenia interfejsu użytkownika (czynności, fragmenty i widoki). W Jetpacku tę rolę pełnią zwykle widoki, które mają dodatkową zaletę w postaci przetrwania zmian konfiguracji (więcej informacji znajdziesz w artykule Omówienie widoku).

Podczas wdrażania układu, który dostosowuje się do różnych rozmiarów, możesz chcieć użyć innego modelu danych na podstawie bieżącego rozmiaru. Jest to jednak sprzeczne z zasadą jednokierunkowego przepływu danych. Dane powinny przepływać w dół do widoków, a zdarzenia takie jak interakcje użytkowników powinny przepływać w górę. Utworzenie zależności w drugim kierunku, w którym model danych zależy od konfiguracji warstwy interfejsu użytkownika, znacznie komplikuje ten proces. Gdy aplikacja zmieni rozmiar, musisz uwzględnić konwersję z jednego modelu danych na inny.

Zamiast tego pozwól, aby model danych uwzględniał największą klasę rozmiarów, a potem możesz selektywnie wyświetlać, ukrywać lub przemieszczać treści w interfejsie, aby dostosować je do bieżącej klasy rozmiarów. Poniżej znajdziesz kilka strategii, których możesz używać, aby określić, jak Twój układ powinien się zachowywać podczas przechodzenia między klasami rozmiarów.

Rozwijanie treści

Kanoniczne układy: kanał

Większa przestrzeń to możliwość powiększenia elementów i zmiany formatu treści, aby były bardziej czytelne.

Zwiększ kolekcje. Wiele aplikacji wyświetla kolekcję elementów w przewijanym kontenerze, takim jak RecyclerView lub ScrollView. Włączenie automatycznego powiększania kontenera oznacza, że można wyświetlać więcej treści. Pamiętaj jednak, aby zawartość w kontenerze nie była zbytnio rozciągnięta ani zniekształcona. Na przykład w przypadku RecyclerView rozważ użycie innego menedżera układu, np. GridLayoutManager, StaggeredGridLayoutManager lub FlexboxLayout, gdy szerokość nie jest kompaktowa.

Złożone i rozłożone urządzenie pokazujące, jak różne menedżery układu wyświetlają aplikację w zależności od klasy rozmiaru szerokości.
Rysunek 2. Różne menedżery układu dla różnych klas rozmiarów okien.

Poszczególne elementy mogą też mieć inny rozmiar lub kształt, aby wyświetlać więcej treści i łatwiej odróżniać ich granice.

Podkreśl element znaczący. Jeśli układ zawiera określony punkt ciężkości, np. obraz lub film, rozwiń go, gdy okno aplikacji się powiększy, aby utrzymać uwagę użytkownika. Inne elementy pomocnicze można przestawiać wokół widoku głównego lub pod nim.

Taki układ można stworzyć na wiele sposobów, ale ConstraintLayout jest szczególnie odpowiedni do tego celu, ponieważ oferuje wiele sposobów na ograniczenie rozmiaru widoku podrzędnego (w tym w procentach lub poprzez wymuszenie proporcji) oraz na pozycjonowanie podrzędnych względem siebie lub innych podrzędnych. Więcej informacji o tych funkcjach znajdziesz w artykule Tworzenie responsywnego interfejsu użytkownika za pomocą ConstraintLayout.

Domyślnie wyświetlaj treści, które można zwinąć. Jeśli jest dostępna sala, wyświetlaj treści, które w innym przypadku byłyby dostępne tylko po wykonaniu przez użytkownika dodatkowej czynności, takiej jak kliknięcie, przewijanie lub gest. Na przykład treści, które w trybie kompaktowym wyświetlają się w interfejsie z kartami, można zamiast tego rozmieścić w kolumnach lub na liście, gdy jest więcej miejsca.

Rozwiń marginesy. Jeśli miejsce jest tak duże, że nie możesz znaleźć odpowiedniego miejsca na wszystkie treści, nawet po wykorzystaniu wszystkich treści, powiększ marginesy układu, aby treści były wyśrodkowane, a poszczególne widoki miały naturalne rozmiary i odstępy.

Komponent pełnoekranowy może też przekształcić się w wyskakujące okienko. Jest to szczególnie przydatne, gdy komponent wymaga wyłącznego skupienia się na wykonaniu bieżącego zadania użytkownika, np. napisaniu e-maila lub utworzeniu wydarzenia w kalendarzu.

Standardowy telefon wyświetlający okno dialogowe na pełnym ekranie oraz rozłożony telefon składany z tym samym oknem w oknie pływającym.
Rysunek 3. okno pełnoekranowe przekształcone w standardowe okno o średniej i rozszerzonej szerokości,

Dodaj treść

Układy kanoniczne: panel pomocniczy, widok listy i widok szczegółów

Użyj okienka pomocniczego. Panel pomocniczy zawiera dodatkowe treści lub kontekstowe działania związane z treściami głównymi, takie jak komentarze w dokumencie lub elementy na playliście. Zazwyczaj zajmują 1/3 dolną część ekranu w przypadku rozszerzonej wysokości lub 1/3 dolnej części ekranu w przypadku rozszerzonej szerokości.

Ważne jest, aby w przypadku braku miejsca na wyświetlenie okna zastanowić się, gdzie umieścić te treści. Oto kilka alternatyw:

  • Panel boczny na krawędzi czołowej za pomocą DrawerLayout
  • Dolna szuflada z użyciem BottomSheetBehavior
  • menu lub wyskakujące okienko dostępne po kliknięciu ikony menu.
Rysunek 4. alternatywne sposoby przedstawiania dodatkowych treści w panelu pomocniczym.

Utwórz układ dwupanelowy. Duże ekrany mogą wyświetlać kombinację funkcji, które na mniejszych ekranach są widoczne osobno. W wielu aplikacjach często występuje taki schemat interakcji: wyświetlana jest lista elementów (np. kontaktów lub wyników wyszukiwania), a po wybraniu elementu wyświetlane są jego szczegóły. Zamiast powiększać listę na większych ekranach, użyj widoku listy z szczegółami, aby wyświetlić obie funkcje obok siebie w układzie z dwoma panelami. W przeciwieństwie do panelu pomocniczego panel szczegółów w widoku listy z informacjami jest elementem samodzielnym, który można wyświetlać niezależnie na mniejszych ekranach.

Użyj dedykowanego widżetu SlidingPaneLayout do implementacji widoku listy z szczegółami. Ten widget automatycznie oblicza, czy jest wystarczająco dużo miejsca na wyświetlenie obu paneli razem, na podstawie wartości layout_width określonej dla obu paneli. Pozostałą przestrzeń można przypisać za pomocą parametru layout_weight. Jeśli nie ma wystarczająco dużo miejsca, każda karta wykorzystuje całą szerokość układu, a karta szczegółów przesuwa się poza ekran lub na wierzch karty listy.

SlidingPaneLayout pokazujący obie części układu listy z szczegółami na urządzeniu z szerokim ekranem.
Rysunek 5. SlidingPaneLayout pokazujący 2 panele w rozszerzonej szerokości i 1 panel w skompresowanej szerokości.

Więcej informacji o używaniu SlidingPaneLayout znajdziesz w artykule Tworzenie układu dwupanelowego. Pamiętaj też, że ten schemat może wpływać na sposób tworzenia grafu nawigacji (patrz Nawigacja w interfejsach elastycznych).

Dodatkowe materiały