Aby zaktualizować układ aplikacji, potrzebujesz różnych informacji, np. o możliwościach urządzenia i stanie aplikacji. Najczęściej używane informacje to szerokość i wysokość okna. Oprócz tego możesz korzystać z tych informacji:
- pozycja okna,
- precyzja urządzeń wskazujących,
- typ klawiatury,
- czy urządzenie obsługuje aparat i mikrofon,
- odległość między użytkownikiem a ekranem urządzenia.
Informacje są aktualizowane dynamicznie, dlatego musisz je monitorować i uruchamiać ponowne komponowanie, gdy nastąpi aktualizacja.
Funkcja mediaQuery abstrahuje szczegóły pobierania informacji
i pozwala skupić się na definiowaniu warunku uruchamiającego aktualizacje układu.
Ten przykład przełącza układ na TabletopLayout, gdy pozycja składanego urządzenia jest ustawiona na stole:
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Włączanie funkcji 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 lambdę
która jest obliczana w UiMediaScope.
Funkcja mediaQuery oblicza 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 |
Aktualna szerokość okna w dp. |
windowHeight |
Dp |
Aktualna wysokość okna w dp. |
windowPosture |
UiMediaScope.Posture |
Aktualna 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 urządzenie obsługuje aparat. |
hasMicrophone |
Boolean |
Czy urządzenie obsługuje mikrofon. |
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
aby uzyskać dostęp do obiektu UiMediaScope,
który reprezentuje aktualne możliwości i kontekst urządzenia.
Ten obiekt jest dynamicznie aktualizowany, gdy wprowadzane są zmiany, np. gdy użytkownik zmienia pozycję urządzenia.
Funkcja mediaQuery oblicza następnie lambdę query za pomocą zaktualizowanego obiektu 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 rozmiarów okien to zestaw opinii na temat punktów przerwania widocznego obszaru
które pomagają projektować, tworzyć i testować układy adaptacyjne.
Możesz porównać 2 parametry reprezentujące aktualny rozmiar okna z progiem zdefiniowanym w klasach rozmiarów okien.
Ten przykład zmienia liczbę paneli w zależności od szerokości okna.
WindowSizeClass klasa ma stałe wartości progowe
klas rozmiarów okien (rysunek 1).
Funkcja derivedMediaQuery oblicza lambdę query
i opakowuje wynik w derivedStateOf.
Ponieważ windowWidth i windowHeight mogą się często zmieniać, w lambdzie query odwołuj się do tych parametrów za pomocą funkcji derivedMediaQuery zamiast 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 pozycji okna
Parametr windowPosture opisuje aktualną pozycję okna jako obiekt UiMediaScope.Posture.
Aktualną pozycję możesz sprawdzić, porównując parametr
z wartościami zdefiniowanymi w klasie UiMediaScope.Posture.
Ten przykład przełącza układ 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 zdefiniowano 4 wartości:
Fine, Coarse, Blunt i None.
None oznacza, że nie jest dostępne żadne urządzenie wskazujące.
Precyzja maleje w tej kolejności: Fine, Coarse i Blunt.
Jeśli dostępnych jest kilka urządzeń wskazujących o różnej precyzji, parametr jest rozwiązywany z najwyższą precyzją.
Jeśli na przykład dostępne są 2 urządzenia wskazujące – jedno o precyzji Fine i jedno o precyzji Blunt – wartością parametru pointerPrecision będzie Fine.
Ten przykład pokazuje większy przycisk, gdy użytkownik używa 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 jednocześnie wyświetlana jest klawiatura ekranowa i dostępna jest klawiatura sprzętowa, parametr jest rozwiązywany jako Physical.
Jeśli nie wykryto żadnej z nich, wartością parametru jest None.
Ten przykład pokazuje komunikat sugerujący podłączenie klawiatury, gdy nie zostanie wykryta żadna klawiatura:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Sprawdzanie, czy urządzenie obsługuje aparat i mikrofon
Niektóre urządzenia nie obsługują aparatów ani mikrofonów.
Możesz sprawdzić, czy urządzenie obsługuje aparat i mikrofon, za pomocą parametrów hasCamera i hasMicrophone.
Ten przykład pokazuje przyciski do użycia z aparatem 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ść 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 zdefiniowano 3 wartości:
Near, Medium i Far.
Near oznacza, że ekran znajduje się w bliskiej odległości, a Far – że urządzenie jest oglądane z daleka.
Ten przykład zwiększa rozmiar czcionki, gdy odległość oglądania jest równa 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 kompozycyjnych.
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 obliczają
podaną lambdę query w obiekcie UiMediaScope,
który jest udostępniany jako LocalUiMediaScope.current.
Możesz go 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 lambdzie treści funkcji
CompositionLocalProvider.
Podgląd TabletopLayout możesz wyświetlić za pomocą 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() } } }