Você precisa de vários tipos de informações, como capacidade do dispositivo e status do app, para atualizar o layout do app. A largura e a altura da janela são as informações mais usadas com frequência. Além disso, consulte as seguintes informações:
- Postura da janela
- Precisão de dispositivos apontadores
- Tipo de teclado
- Se a câmera e o microfone são compatíveis com o dispositivo
- A distância entre um usuário e a tela do dispositivo
Como as informações são atualizadas dinamicamente, é necessário monitorá-las e acionar a recomposição quando houver uma atualização.
A função mediaQuery abstrai os detalhes da recuperação de informações
e permite que você se concentre na definição da condição para acionar as atualizações de layout.
O exemplo a seguir muda o layout para TabletopLayout
quando a postura do dobrável é de mesa:
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Ativar a função mediaQuery
Para ativar a função mediaQuery,
defina o atributo isMediaQueryIntegrationEnabled do
objeto ComposeUiFlags como true:
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
Definir uma condição com parâmetros
Você pode definir uma condição como uma lambda
que é avaliada em UiMediaScope.
A função mediaQuery avalia a condição de acordo com o status atual e os recursos do dispositivo.
A função retorna um valor booleano. Assim, é possível determinar o layout com ramificações condicionais, como uma expressão if.
A Tabela 1 descreve os parâmetros disponíveis em UiMediaScope.
| Parâmetro | Tipo de valor | Descrição |
|---|---|---|
windowWidth |
Dp |
A largura atual da janela em dp. |
windowHeight |
Dp |
A altura atual da janela em dp. |
windowPosture |
UiMediaScope.Posture |
A postura atual da janela do aplicativo. |
pointerPrecision |
UiMediaScope.PointerPrecision |
A maior precisão dos dispositivos apontadores disponíveis. |
keyboardKind |
UiMediaScope.KeyboardKind |
O tipo de teclado disponível ou conectado. |
hasCamera |
Boolean |
Se a câmera é compatível com o dispositivo. |
hasMicrophone |
Boolean |
Se o microfone é compatível com o dispositivo. |
viewingDistance |
UiMediaScope.ViewingDistance |
A distância típica entre o usuário e a tela do dispositivo. |
Um objeto UiMediaScope resolve os valores dos parâmetros.
A função mediaQuery usa LocalUiMediaScope.current
para acessar o objeto UiMediaScope,
que representa os recursos e o contexto do dispositivo atual.
Esse objeto é atualizado dinamicamente quando são feitas mudanças,
como quando o usuário muda a postura do dispositivo.
Em seguida, a função mediaQuery avalia a lambda query com o objeto UiMediaScope atualizado e retorna um valor booleano.
Por exemplo, o trecho a seguir escolhe entre TabletopLayout
e FlatLayout com base no valor do parâmetro windowPosture.
@Composable fun VideoPlayer( // ... ) { // ... if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) { TabletopLayout() } else { FlatLayout() } // ... }
Tomar uma decisão com base no tamanho da janela
As classes de tamanho de janela são um conjunto de pontos de interrupção específicos da janela de visualização
que ajudam você a projetar, desenvolver e testar layouts adaptáveis.
É possível comparar os dois parâmetros que representam o tamanho da janela atual com o limite definido nas classes de tamanho de janela.
O exemplo a seguir muda o número de painéis de acordo com a largura da janela.
A classe WindowSizeClass tem constantes para os limites das classes de tamanho de janela (Figura 1).
A função derivedMediaQuery avalia a lambda query
e encapsula o resultado em um derivedStateOf.
Como windowWidth e windowHeight podem ser atualizados com frequência, chame a função derivedMediaQuery em vez de mediaQuery ao se referir a esses parâmetros na lambda query.
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() }
Atualizar o layout de acordo com a postura da janela
O parâmetro windowPosture descreve a postura da janela atual como um objeto UiMediaScope.Posture.
Para verificar a postura atual, compare o parâmetro com os valores definidos na classe UiMediaScope.Posture.
O exemplo a seguir muda o layout de acordo com a postura da janela:
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
Verificar a precisão do dispositivo apontador disponível
Um dispositivo apontador de alta precisão ajuda os usuários a apontar um elemento da interface com precisão. A precisão de um dispositivo apontador depende do tipo de dispositivo.
O parâmetro pointerPrecision descreve a precisão dos dispositivos apontadores disponíveis, como um mouse e uma tela touchscreen.
Há quatro valores definidos na classe UiMediaScope.PointerPrecision:
Fine, Coarse, Blunt e None.
None significa que nenhum dispositivo apontador está disponível.
A precisão varia do mais alto ao mais baixo nesta ordem: Fine, Coarse e Blunt.
Se houver vários dispositivos apontadores disponíveis e as precisões forem diferentes, o parâmetro será resolvido com a mais alta.
Por exemplo, se houver dois dispositivos apontadores, um de precisão Fine e outro de precisão Blunt, Fine será o valor do parâmetro pointerPrecision.
O exemplo a seguir mostra um botão maior quando o usuário está usando um dispositivo apontador com baixa precisão:
if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) { LargeSizeButton() } else { NormalSizeButton() }
Verificar o tipo de teclado disponível
O parâmetro keyboardKind representa o tipo de teclado disponível: Physical, Virtual e None.
Se um teclado na tela for mostrado e um teclado físico estiver disponível ao mesmo tempo, o parâmetro será resolvido como Physical.
Se nenhum deles for detectado, None será o valor do parâmetro.
O exemplo a seguir mostra uma mensagem sugerindo que os usuários conectem um teclado
quando nenhum teclado é detectado:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Verificar se o dispositivo é compatível com câmera e microfone
Alguns dispositivos não são compatíveis com câmeras ou microfones.
Você pode verificar se o dispositivo é compatível com uma câmera e um microfone
com os parâmetros hasCamera e hasMicrophone.
O exemplo a seguir mostra botões para usar com câmera e microfone
quando o dispositivo oferece suporte a eles:
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() } }
Ajustar a interface com a distância de visualização estimada
A distância de visualização é um fator que ajuda a determinar o layout.
Se o usuário estiver usando o app de longe,
ele vai esperar que o texto e os elementos da interface sejam maiores.
O parâmetro viewingDistance fornece uma estimativa da distância de visualização com base no tipo de dispositivo e no contexto de uso típico dele.
Há três valores definidos na classe UiMediaScope.ViewingDistance:
Near, Medium e Far.
Near significa que a tela está perto,
e Far significa que o dispositivo está sendo visto de longe.
O exemplo a seguir aumenta o tamanho da fonte quando a distância de visualização é Far ou Medium:
val fontSize = when { mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp else -> 16.sp }
Visualizar um componente de UI
Você pode chamar as funções mediaQuery e derivedMediaQuery nas funções combináveis para visualizar os componentes da interface.
O snippet a seguir escolhe entre TabletopLayout
e FlatLayout com base no valor de parâmetro windowPosture.
Para visualizar o TabletopLayout, o parâmetro windowPosture precisa ser
UiMediaScope.Posture.Tabletop.
when { mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout() mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout() }
As funções mediaQuery e derivedMediaQuery avaliam a lambda query fornecida em um objeto UiMediaScope, que é fornecido como LocalUiMediaScope.current.
Para substituir, siga estas etapas:
- Ative a função
mediaQuery. - Defina um objeto personalizado que implemente a interface
UiMediaScope. - Defina o objeto personalizado como
LocalUiMediaScopecom a funçãoCompositionLocalProvider. - Chame o elemento combinável para visualizar na lambda de conteúdo da função
CompositionLocalProvider.
Você pode visualizar o TabletopLayout com o exemplo a seguir:
@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() } } }