Você precisa de vários tipos de informações, como a capacidade do dispositivo e o status do app, para atualizar o layout. A largura e a altura da janela são as informações mais usadas com frequência. Além disso, você pode consultar as seguintes informações:
- Posição da janela
- Precisão dos 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 posição 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 de
o objeto ComposeUiFlags como true:
class MyApplication : Application() { override fun onCreate() { ComposeUiFlags.isMediaQueryIntegrationEnabled = true super.onCreate() } }
Definir uma condição com parâmetros
É possível definir uma condição como uma lambda
avaliada em UiMediaScope.
A função mediaQuery avalia a condição de acordo com o status atual e as capacidades do dispositivo.
A função retorna um valor booleano, então você pode 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 posição 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 as capacidades e o contexto do dispositivo atual.
Esse objeto é atualizado dinamicamente quando são feitas mudanças, como quando o usuário muda a posição do dispositivo.
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
Classes de tamanho de janela são um conjunto de pontos de interrupção específicos de 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 atual da janela 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.
WindowSizeClass classe tem constantes para os limites
das classes de tamanho de janela (Figura 1).
A função derivedMediaQuery avalia a lambda query
e envolve o resultado em um derivedStateOf.
Como windowWidth e windowHeight podem ser atualizados com frequência, chame a função derivedMediaQuery em vez da função mediaQuery quando você 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 posição da janela
O parâmetro windowPosture descreve a posição atual da janela como um objeto UiMediaScope.Posture.
É possível verificar a postura atual comparando o parâmetro
com os valores definidos na UiMediaScope.Posture classe.
O exemplo a seguir muda o layout de acordo com a posição 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 sensível ao toque.
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 de maior para menor nesta ordem: Fine, Coarse e Blunt.
Se vários dispositivos apontadores estiverem disponíveis e as precisões forem diferentes, o parâmetro será resolvido com o mais alto.
Por exemplo, se houver dois dispositivos apontadores, um dispositivo de precisão Fine e um dispositivo 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 teclados disponíveis:
Physical, Virtual e None.
Se um teclado na tela for exibido e um teclado de hardware estiver disponível ao mesmo tempo, o parâmetro será resolvido como Physical.
Se nenhum 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 for detectado:
if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) { SuggestKeyboardConnect() }
Verificar se o dispositivo oferece suporte à câmera e ao microfone
Alguns dispositivos não oferecem suporte a câmeras ou microfones.
É possível verificar se o dispositivo oferece suporte a uma câmera e um microfone com o parâmetro hasCamera e o parâmetro hasMicrophone.
O exemplo a seguir mostra botões para usar com a câmera e o 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 à distância, 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.
Há três valores definidos na classe UiMediaScope.ViewingDistance:
Near, Medium e Far.
Near significa que a tela está em um alcance próximo, e Far significa que o dispositivo é visualizado à distância.
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 da interface
É possível chamar as funções mediaQuery e derivedMediaQuery nas funções combináveis para visualizar 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.
É possível substituir isso seguindo estas etapas:
- Ativar a função
mediaQuery. - Defina um objeto personalizado que implemente a interface
UiMediaScope. - Defina o objeto personalizado como o
LocalUiMediaScopecom a funçãoCompositionLocalProvider. - Chame o combinável para visualizar na lambda de conteúdo da função
CompositionLocalProvider.
É possível 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() } } }