Obsługa różnych rozmiarów wyświetlaczy umożliwia dostęp do aplikacji na najróżniejszych urządzeniach i największej liczbie użytkowników.
Aby obsługiwać jak najwięcej rozmiarów wyświetlaczy – zarówno na różnych ekranach urządzeń, jak i w różnych oknach aplikacji w trybie wielu okien – zaprojektuj układy aplikacji tak, aby były elastyczne i adaptacyjne. Układy elastyczne/adaptacyjne zapewniają optymalne wrażenia użytkownika niezależnie od rozmiaru wyświetlacza, dzięki czemu aplikacja może dostosowywać się do telefonów, tabletów, urządzeń składanych, urządzeń z ChromeOS, orientacji pionowej i poziomej oraz konfiguracji wyświetlacza z możliwością zmiany rozmiaru, takich jak tryb podzielonego ekranu i tryb okien na pulpicie.
Układy elastyczne/adaptacyjne zmieniają się w zależności od dostępnego miejsca na ekranie. Zmiany mogą obejmować zarówno niewielkie korekty układu, które wypełniają przestrzeń (elastyczne projektowanie stron), jak i całkowite zastąpienie jednego układu innym, aby aplikacja mogła jak najlepiej dostosować się do różnych rozmiarów wyświetlacza (projektowanie adaptacyjne).
Jetpack Compose to deklaratywny zestaw narzędzi do tworzenia interfejsu, który idealnie nadaje się do projektowania i wdrażania układów dynamicznie zmieniających się w celu renderowania treści w różny sposób na różnych rozmiarach wyświetlacza.
Umiejętności związane z Androidem
Wyświetl na GitHubieDostosowywanie aplikacji
adaptive, aby zaktualizować interfejs aplikacji i dostosować go do różnych urządzeń z Androidem i wyświetlaczy.android skills add adaptiveWyraźne wprowadzanie dużych zmian w układzie elementów kompozycyjnych na poziomie treści
Komponenty na poziomie aplikacji i treści zajmują całą przestrzeń wyświetlania dostępną dla aplikacji. W przypadku tych typów komponentów warto zmienić ogólny układ aplikacji na dużych wyświetlaczach.
Unikaj podejmowania decyzji dotyczących układu na podstawie fizycznych wartości sprzętu. Może kusić Cię podejmowanie decyzji na podstawie stałej, wymiernej wartości (czy urządzenie jest tabletem? Czy fizyczny ekran ma określony format obrazu?), ale odpowiedzi na te pytania mogą nie być przydatne do określenia miejsca dostępnego dla interfejsu.
Na tabletach aplikacja może działać w trybie wielu okien, co oznacza, że może dzielić ekran z inną aplikacją. W trybie okien na pulpicie lub w ChromeOS aplikacja może być wyświetlana w oknie z możliwością zmiany rozmiaru. Może być nawet więcej niż 1 ekran fizyczny, np. w przypadku urządzenia składanego. We wszystkich tych przypadkach fizyczny rozmiar ekranu nie ma znaczenia przy podejmowaniu decyzji o sposobie wyświetlania treści.
Zamiast tego podejmuj decyzje na podstawie rzeczywistej części ekranu przydzielonej aplikacji, która jest opisana przez bieżące dane okna dostarczane przez bibliotekę WindowManager Jetpacka. Przykład użycia WindowManager w aplikacji Compose znajdziesz w przykładowej aplikacji JetNews.
Dostosowanie układów do dostępnej przestrzeni wyświetlania zmniejsza też ilość specjalnych działań wymaganych do obsługi platform takich jak ChromeOS i formatów takich jak tablety i urządzenia składane.
Po określeniu danych dotyczących miejsca dostępnego dla aplikacji przekonwertuj nieprzetworzony rozmiar na klasę rozmiaru okna zgodnie z opisem w artykule Korzystanie z klas rozmiaru okna. Klasy rozmiaru okna to punkty przerwania, które mają na celu zachowanie równowagi między prostotą logiki aplikacji a elastycznością optymalizacji aplikacji pod kątem większości rozmiarów wyświetlaczy.
Klasy rozmiaru okna odnoszą się do ogólnego okna aplikacji, więc używaj ich do podejmowania decyzji dotyczących układu, które wpływają na ogólny układ aplikacji. Możesz przekazywać klasy rozmiaru okna jako stan lub wykonać dodatkową logikę, aby utworzyć stan pochodny, który zostanie przekazany do zagnieżdżonych funkcji kompozycyjnych.
@Composable fun MyApp( windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true).windowSizeClass ) { // Decide whether to show the top app bar based on window size class. val showTopAppBar = windowSizeClass.isHeightAtLeastBreakpoint(WindowSizeClass.HEIGHT_DP_MEDIUM_LOWER_BOUND) // MyScreen logic is based on the showTopAppBar boolean flag. MyScreen( showTopAppBar = showTopAppBar, /* ... */ ) }
Podejście warstwowe ogranicza logikę rozmiaru wyświetlacza do jednej lokalizacji, zamiast rozpraszać ją po aplikacji w wielu miejscach, które muszą być zsynchronizowane. W jednym miejscu jest generowany stan, który można jawnie przekazać do innych funkcji kompozycyjnych, tak jak każdy inny stan aplikacji. Jawne przekazywanie stanu upraszcza poszczególne elementy kompozycyjne, ponieważ przyjmują one klasę rozmiaru okna lub określoną konfigurację wraz z innymi danymi.
Elastyczne zagnieżdżone funkcje kompozycyjne można wykorzystywać wielokrotnie
Komponenty kompozycyjne można wielokrotnie wykorzystywać, gdy można je umieścić w wielu różnych miejscach. Jeśli element kompozycyjny musi być umieszczony w określonym miejscu i mieć określony rozmiar, prawdopodobnie nie będzie można go użyć w innych kontekstach. Oznacza to również, że poszczególne elementy kompozycyjne wielokrotnego użytku nie powinny być zależne od globalnych informacji o rozmiarze wyświetlacza.
Wyobraź sobie zagnieżdżony element kompozycyjny, który implementuje szczegółową listę, która może wyświetlać 1 panel lub 2 panele obok siebie:
Decyzja o wyświetlaniu listy i szczegółów powinna być częścią ogólnego układu aplikacji, więc jest przekazywana z funkcji kompozycyjnej na poziomie treści:
@Composable fun AdaptivePane( showOnePane: Boolean, /* ... */ ) { if (showOnePane) { OnePane(/* ... */) } else { TwoPane(/* ... */) } }
Co zrobić, jeśli chcesz, aby funkcja kompozycyjna niezależnie zmieniała układ na podstawie dostępnego miejsca na ekranie, np. karta, która wyświetla dodatkowe szczegóły, jeśli jest na to miejsce? Chcesz wykonać pewne działania logiczne na podstawie dostępnego rozmiaru wyświetlania, ale o jaki rozmiar chodzi?
Nie próbuj używać rozmiaru rzeczywistego ekranu urządzenia. Nie będzie to dokładne w przypadku różnych typów ekranów ani wtedy, gdy aplikacja nie jest wyświetlana na pełnym ekranie.
Ponieważ funkcja kompozycyjna nie jest funkcją kompozycyjną na poziomie treści, nie używaj bezpośrednio danych bieżącego okna.
Jeśli komponent jest umieszczony z dopełnieniem (np. z wstawkami) lub jeśli aplikacja zawiera komponenty takie jak szyny nawigacyjne lub paski aplikacji, ilość miejsca na ekranie dostępnego dla funkcji kompozycyjnej może się znacznie różnić od ogólnej ilości miejsca dostępnego dla aplikacji.
Użyj szerokości, która jest faktycznie przypisana do funkcji kompozycyjnej, aby ją wyrenderować. Możesz uzyskać tę szerokość na 2 sposoby:
Jeśli chcesz zmienić miejsce lub sposób wyświetlania treści, użyj kolekcji modyfikatorów lub niestandardowego układu, aby układ był elastyczny. Może to być tak proste jak wypełnienie przez element podrzędny całej dostępnej przestrzeni lub rozmieszczenie elementów podrzędnych w wielu kolumnach, jeśli jest wystarczająco dużo miejsca.
Jeśli chcesz zmienić to, co wyświetlasz, użyj
BoxWithConstraintsjako bardziej zaawansowanej alternatywy.BoxWithConstraintsudostępnia ograniczenia pomiarowe, których możesz używać do wywoływania różnych funkcji kompozycyjnych na podstawie dostępnego miejsca na ekranie. Ma to jednak swoją cenę, ponieważBoxWithConstraintsopóźnia kompozycję do fazy układu, gdy te ograniczenia są znane, co powoduje, że podczas układu wykonywana jest większa ilość pracy.
@Composable fun Card(/* ... */) { BoxWithConstraints { if (maxWidth < 400.dp) { Column { Image(/* ... */) Title(/* ... */) } } else { Row { Column { Title(/* ... */) Description(/* ... */) } Image(/* ... */) } } } }
Udostępnianie wszystkich danych na ekranach o różnych rozmiarach
Podczas implementowania funkcji kompozycyjnej, która wykorzystuje dodatkową przestrzeń wyświetlacza, możesz ulec pokusie, aby zwiększyć wydajność i wczytywać dane jako efekt uboczny bieżącego rozmiaru wyświetlacza.
Jest to jednak sprzeczne z zasadą jednokierunkowego przepływu danych, zgodnie z którą dane mogą być przenoszone i przekazywane do funkcji kompozycyjnych w celu odpowiedniego renderowania. Do funkcji kompozycyjnej należy przekazać wystarczającą ilość danych, aby zawsze miała wystarczającą ilość treści dla dowolnego rozmiaru wyświetlacza, nawet jeśli niektóre części treści nie zawsze będą używane.
@Composable fun Card( imageUrl: String, title: String, description: String ) { BoxWithConstraints { if (maxWidth < 400.dp) { Column { Image(imageUrl) Title(title) } } else { Row { Column { Title(title) Description(description) } Image(imageUrl) } } } }
Wracając do przykładu Card, zauważ, że description jest zawsze przekazywany do Card. Mimo że właściwość description jest używana tylko wtedy, gdy szerokość pozwala na jej wyświetlenie, właściwość Card zawsze wymaga właściwości description, niezależnie od dostępnej szerokości.
Zawsze przekazuj wystarczającą ilość treści, aby uprościć układy adaptacyjne, zmniejszając ich stanowość i unikając wywoływania efektów ubocznych podczas przełączania się między rozmiarami wyświetlacza (co może nastąpić z powodu zmiany rozmiaru okna, zmiany orientacji lub złożenia i rozłożenia urządzenia).
Ta zasada pozwala też zachować stan podczas zmian układu. Przez przeniesienie informacji, które mogą nie być używane we wszystkich rozmiarach wyświetlacza, możesz zachować stan aplikacji, gdy zmienia się rozmiar układu.
Możesz na przykład podnieść flagę logiczną showMore, aby stan aplikacji został zachowany, gdy zmiana rozmiaru wyświetlacza spowoduje przełączenie układu między ukrywaniem a wyświetlaniem treści:
@Composable fun Card( imageUrl: String, title: String, description: String ) { var showMore by remember { mutableStateOf(false) } BoxWithConstraints { if (maxWidth < 400.dp) { Column { Image(imageUrl) Title(title) } } else { Row { Column { Title(title) Description( description = description, showMore = showMore, onShowMoreToggled = { newValue -> showMore = newValue } ) } Image(imageUrl) } } } }
Więcej informacji
Więcej informacji o układach adaptacyjnych w Compose znajdziesz w tych materiałach:
Przykładowe aplikacje
- CanonicalLayouts to repozytorium sprawdzonych wzorców projektowych, które zapewniają optymalne wrażenia użytkownikom na dużych wyświetlaczach.
- JetNews pokazuje, jak zaprojektować aplikację, która dostosowuje interfejs, aby wykorzystać dostępną przestrzeń wyświetlania.
- Reply to adaptacyjny przykład obsługi urządzeń mobilnych, tabletów i urządzeń składanych.
- Now in Android to aplikacja, która używa układów adaptacyjnych do obsługi różnych rozmiarów wyświetlaczy.
Filmy