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:
- Pozycja okna
- Precyzja urządzeń wskazujących
- Typ klawiatury
- Czy urządzenie obsługuje kamerę i mikrofon.
- odległość między użytkownikiem a wyświetlaczem urządzenia,
Informacje są aktualizowane dynamicznie, więc musisz je monitorować i wywoływać rekompozycję po każdej aktualizacji.
Funkcja mediaQuery abstrahuje szczegóły pobierania informacji i pozwala skupić się na definiowaniu warunku aktywującego aktualizacje układu.
W tym przykładzie układ zmienia się na TabletopLayout, gdy urządzenie składane jest w trybie 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() } }
Definiowanie warunku z parametrami
Warunek możesz zdefiniować jako funkcję lambda, która jest oceniana w ramach UiMediaScope.
Funkcja mediaQuery ocenia warunek na podstawie bieżącego stanu i możliwości urządzenia.
Funkcja zwraca wartość logiczną,
dzięki czemu możesz określić układ za pomocą gałęzi 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 |
Bieżący stan okna aplikacji. |
pointerPrecision |
UiMediaScope.PointerPrecision |
Najwyższa precyzja spośród 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 rozpoznaje wartości parametrów.
Funkcja mediaQuery używa LocalUiMediaScope.current, aby uzyskać dostęp do obiektu UiMediaScope, który reprezentuje bieżące możliwości i kontekst urządzenia.
Ten obiekt jest aktualizowany dynamicznie, gdy wprowadzane są zmiany, np. gdy użytkownik zmienia pozycję urządzenia.
Funkcja mediaQuery ocenia następnie funkcję lambda query ze zaktualizowanym obiektem UiMediaScope i zwraca wartość logiczną.
Na przykład ten fragment kodu wybiera między TabletopLayout a 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 rozmiaru okna to zestaw 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 progiem zdefiniowanym w klasach rozmiaru okna.
W poniższym przykładzie liczba paneli zmienia się w zależności od szerokości okna.
Klasa WindowSizeClass zawiera stałe dla progów klas rozmiaru okna (rysunek 1).
Funkcja derivedMediaQuery ocenia funkcję lambda query i opakowuje wynik w derivedStateOf.
Ponieważ parametry windowWidth i windowHeight mogą być często aktualizowane,
gdy odwołujesz się do nich w funkcji lambda query,
wywołaj 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 zgodnie z położeniem okna
Parametr windowPosture opisuje bieżący układ okna jako obiekt UiMediaScope.Posture.
Możesz sprawdzić bieżący stan, 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 pozycji 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 precyzyjnie 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 jest dostępne żadne urządzenie wskazujące.
Precyzja jest podawana w kolejności od najwyższej do najniższej: Fine, Coarse i Blunt.
Jeśli dostępnych jest kilka urządzeń wskazujących o różnej precyzji, parametr jest określany na podstawie najwyższej z nich.
Jeśli na przykład są 2 urządzenia wskazujące – jedno o precyzji Fine, a drugie o precyzji 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 jednocześnie dostępna jest klawiatura sprzętowa, parametr jest rozpoznawany jako Physical.
Jeśli nie zostanie wykryty żaden z tych elementów, wartością parametru będzie None.
Poniższy przykład pokazuje komunikat sugerujący użytkownikom podłączenie klawiatury, gdy nie zostanie ona wykryta:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Sprawdzanie, 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.
W tym przykładzie pokazano przyciski, których można używać 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 do szacowanej odległości oglądania
Odległość od ekranu jest czynnikiem, który pomaga określić układ.
Jeśli użytkownik korzysta z aplikacji z pewnej odległości,
będzie oczekiwać, że tekst i elementy interfejsu będą większe.
Parametr viewingDistance podaje 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 blisko, a Far – że urządzenie jest oglądane z daleka.
W tym przykładzie rozmiar czcionki zwiększa się, 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
Aby wyświetlić podgląd komponentów interfejsu, możesz wywołać funkcje mediaQuery i derivedMediaQuery w funkcjach typu „composable”.
Ten 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 oceniają podaną funkcję lambda query w obiekcie UiMediaScope, który jest podany jako LocalUiMediaScope.current.
Możesz je 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 element kompozycyjny, aby wyświetlić podgląd w funkcji lambda treści funkcji
CompositionLocalProvider.
Możesz wyświetlić podgląd TabletopLayout, korzystając z tego przykładu:
@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() } } }