Aby zaktualizować układ aplikacji, potrzebujesz różnych informacji, takich jak możliwości urządzenia i stan aplikacji. Najczęściej używane informacje to szerokość i wysokość okna. Możesz też zapoznać się z tymi informacjami:
- Położenie okna
- Precyzja urządzeń wskazujących
- Typ klawiatury
- Czy aparat i mikrofon są obsługiwane przez urządzenie.
- odległość między użytkownikiem a wyświetlaczem urządzenia,
Informacje są aktualizowane dynamicznie, dlatego musisz je monitorować i wywoływać ponowne komponowanie, gdy tylko nastąpi aktualizacja.
Funkcja mediaQuery abstrahuje od szczegółów pobierania informacji i pozwala skupić się na definiowaniu warunku wywołującego aktualizacje układu.
W poniższym przykładzie układ przełącza się na TabletopLayout, gdy urządzenie składane jest w pozycji na stole:
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Włącz funkcję mediaQuery
Aby włączyć funkcję mediaQuery, ustaw atrybut isMediaQueryIntegrationEnabled obiektu ComposeUiFlags na true:
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
Określanie warunku za pomocą parametrów
Warunek możesz zdefiniować jako funkcję lambda, która jest oceniana w UiMediaScope.
Funkcja mediaQuery ocenia warunek na podstawie bieżącego stanu i możliwości urządzenia.
Funkcja zwraca wartość logiczną, więc możesz określić układ za pomocą rozgałęzień warunkowych, takich jak wyrażenie if.
Tabela 1 zawiera opis parametrów dostępnych w UiMediaScope.
| Parametr | Typ wartości | Opis |
|---|---|---|
windowWidth |
Dp |
Bieżąca szerokość okna w dp. |
windowHeight |
Dp |
Bieżąca wysokość okna w dp. |
windowPosture |
UiMediaScope.Posture |
Obecna pozycja okna aplikacji. |
pointerPrecision |
UiMediaScope.PointerPrecision |
Najwyższa precyzja dostępnych urządzeń wskazujących. |
keyboardKind |
UiMediaScope.KeyboardKind |
Typ dostępnej lub podłączonej klawiatury. |
hasCamera |
Boolean |
Czy aparat jest obsługiwany na urządzeniu. |
hasMicrophone |
Boolean |
Czy mikrofon jest obsługiwany na urządzeniu. |
viewingDistance |
UiMediaScope.ViewingDistance |
Typowa odległość między użytkownikiem a ekranem urządzenia. |
Obiekt UiMediaScope rozwiązuje wartości parametrów.
Funkcja mediaQuery używa LocalUiMediaScope.current do uzyskiwania dostępu do obiektu UiMediaScope, który reprezentuje bieżące możliwości i kontekst urządzenia.
Ten obiekt jest dynamicznie aktualizowany po wprowadzeniu jakichkolwiek zmian, np. gdy użytkownik zmieni położenie urządzenia.
Funkcja mediaQuery oblicza następnie wyrażenie lambda query z zaktualizowanym obiektem UiMediaScope i zwraca wartość logiczną.
Na przykład ten fragment kodu wybiera wartość TabletopLayout lub FlatLayout na podstawie wartości parametru windowPosture.
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Podejmowanie decyzji na podstawie rozmiaru okna
Klasy rozmiarów okien to zestaw opartych na opiniach punktów przerwania widocznego obszaru, które pomagają projektować, tworzyć i testować układy adaptacyjne.
Możesz porównać 2 parametry reprezentujące bieżący rozmiar okna z wartością progową zdefiniowaną w klasach rozmiarów okna.
W tym przykładzie liczba paneli zmienia się w zależności od szerokości okna.
Klasa WindowSizeClass zawiera stałe wartości progowe klas rozmiaru okna (rysunek 1).
Funkcja derivedMediaQuery oblicza wartość wyrażenia lambda query i zawiera wynik w funkcji derivedStateOf.
Ponieważ funkcje windowWidth i windowHeight mogą być często aktualizowane, w przypadku odwoływania się do tych parametrów w funkcji query lambda wywołuj funkcję derivedMediaQuery zamiast funkcji mediaQuery.
val narrowerThanMedium by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp } val narrowerThanExpanded by derivedMediaQuery { windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp } when { narrowerThanMedium -> SinglePaneLayout() narrowerThanExpanded -> TwoPaneLayout() else -> ThreePaneLayout() }
Aktualizowanie układu w zależności od położenia okna
Parametr windowPosture opisuje aktualną pozycję okna jako obiekt UiMediaScope.Posture.
Aktualną postawę możesz sprawdzić, porównując parametr z wartościami zdefiniowanymi w klasie UiMediaScope.Posture.
W tym przykładzie układ zmienia się w zależności od orientacji okna:
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
Sprawdzanie precyzji dostępnego urządzenia wskazującego
Urządzenie wskazujące o wysokiej precyzji pomaga użytkownikom dokładnie wskazywać elementy interfejsu. Precyzja urządzenia wskazującego zależy od jego typu.
Parametr pointerPrecision opisuje precyzję dostępnych urządzeń wskazujących, takich jak mysz i ekran dotykowy.
W klasie UiMediaScope.PointerPrecision zdefiniowane są 4 wartości: Fine, Coarse, Blunt i None.
None oznacza, że nie ma dostępnego urządzenia wskazującego.
Precyzja jest największa w przypadku tych wartości, a najmniejsza w przypadku tych: Fine, Coarse i Blunt.
Jeśli dostępnych jest kilka urządzeń wskazujących o różnej precyzji, parametr jest rozwiązywany z użyciem najwyższej precyzji.
Jeśli na przykład są 2 urządzenia wskazujące — Fine i Blunt — wartością parametru pointerPrecision jest Fine.
Poniższy przykład pokazuje większy przycisk, gdy użytkownik korzysta z urządzenia wskazującego o niskiej precyzji:
if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) { LargeSizeButton() } else { NormalSizeButton() }
Sprawdzanie dostępnego typu klawiatury
Parametr keyboardKind reprezentuje typ dostępnych klawiatur: Physical, Virtual i None.
Jeśli klawiatura ekranowa jest wyświetlana, a klawiatura sprzętowa jest dostępna w tym samym czasie, parametr jest rozpoznawany jako Physical.
Jeśli nie zostanie wykryta żadna z tych wartości, parametrem będzie None.
Poniżej znajdziesz przykład komunikatu sugerującego podłączenie klawiatury, gdy nie jest ona wykrywana:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Sprawdź, czy urządzenie obsługuje aparat i mikrofon.
Niektóre urządzenia nie obsługują kamer ani mikrofonów.
Możesz sprawdzić, czy urządzenie obsługuje kamerę i mikrofon, za pomocą parametrów hasCamera i hasMicrophone.
Ten przykład pokazuje przyciski do użycia z kamerą i mikrofonem, gdy urządzenie je obsługuje:
Row { OutlinedTextField(state = rememberTextFieldState()) // Show the MicButton when the device supports a microphone. if (mediaQuery { hasMicrophone }) { MicButton() } // Show the CameraButton when the device supports a camera. if (mediaQuery { hasCamera }) { CameraButton() } }
Dostosowywanie interfejsu na podstawie szacowanej odległości oglądania
Odległość oglądania to czynnik, który pomaga określić układ.
Jeśli użytkownik korzysta z aplikacji z daleka, oczekuje, że tekst i elementy interfejsu będą większe.
Parametr viewingDistance zawiera szacunkową odległość oglądania na podstawie typu urządzenia i typowego kontekstu jego użycia.
W klasie UiMediaScope.ViewingDistance zdefiniowane są 3 wartości:Near, Medium i Far.
Near oznacza, że ekran jest w pobliżu, a Far oznacza, że urządzenie jest oglądane z daleka.
W tym przykładzie zwiększamy rozmiar czcionki, gdy odległość od ekranu wynosi Far lub Medium:
val fontSize = when { mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp else -> 16.sp }
Wyświetlanie podglądu komponentu interfejsu
W funkcjach kompozycyjnych możesz wywoływać funkcje mediaQuery i derivedMediaQuery, aby wyświetlać podgląd komponentów interfejsu.
Poniższy fragment kodu wybiera między TabletopLayout a FlatLayout na podstawie wartości parametru windowPosture.
Aby wyświetlić podgląd TabletopLayout, parametr windowPosture powinien mieć wartość UiMediaScope.Posture.Tabletop.
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
Funkcje mediaQuery i derivedMediaQuery obliczają daną funkcję lambda query w obiekcie UiMediaScope, który jest podany jako LocalUiMediaScope.current.
Możesz ją zastąpić, wykonując te czynności:
- Włącz funkcję
mediaQuery. - Zdefiniuj obiekt niestandardowy, który implementuje interfejs
UiMediaScope. - Ustaw obiekt niestandardowy na
LocalUiMediaScopeza pomocą funkcjiCompositionLocalProvider. - Wywołaj funkcję kompozycyjną, aby wyświetlić podgląd w treści lambda funkcji
CompositionLocalProvider.
Podgląd atrybutu TabletopLayout możesz zobaczyć na tym przykładzie:
@Preview @Composable fun PreviewLayoutForTabletop() { // Step 1: Enable the mediaQuery function ComposeUiFlags.isMediaQueryIntegrationEnabled = true val currentUiMediaScope = LocalUiMediaScope.current // Step 2: Define a custom object implementing the UiMediaScope interface. // The object overrides the windowPosture parameter. // The resolution of the remaining parameters is deferred to the currentUiMediaScope object. val uiMediaScope = remember(currentUiMediaScope) { object : UiMediaScope by currentUiMediaScope { override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop } } // Step 3: Set the object to the LocalUiMediaScope. CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) { // Step 4: Call the composable to preview. when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() } } }