WindowInsets
é a API padrão no Jetpack Compose para processar
áreas da tela que estão parcial ou totalmente obscurecidas pela interface do sistema. Essas
áreas incluem a barra de status, a barra de navegação e o teclado na tela. Você também pode transmitir WindowInsetsRulers
predefinidos, como SafeDrawing
, para Modifier.fitInside
ou Modifier.fitOutside
, e alinhar seu conteúdo com as barras de sistema e o corte da tela ou criar WindowInsetsRulers
personalizados.
Vantagens do WindowInsetsRulers
- Evita a complexidade de consumo: opera durante a fase de posicionamento do layout. Isso significa que ele ignora completamente a cadeia de consumo de encartes e sempre pode fornecer as posições corretas e absolutas das barras de sistema e dos cortes da tela, independente do que os layouts principais fizeram. Usar os métodos
Modifier.fitInside
ouModifier.fitOutside
ajuda a corrigir problemas quando elementos combináveis ancestrais consomem insets incorretamente. - Evite facilmente as barras de sistema: ajuda o conteúdo do app a evitar as barras de sistema
e o corte da tela, além de ser mais simples do que usar
WindowInsets
diretamente. - Altamente personalizável: os desenvolvedores podem alinhar o conteúdo a réguas personalizadas e ter controle preciso sobre os layouts com layouts personalizados.
Desvantagens do WindowInsetsRulers
- Não pode ser usado para medição: como opera durante a fase de posicionamento, as informações de posição que ele fornece não estão disponíveis durante a fase de medição anterior.
Alinhe seu conteúdo com métodos de modificador
O Modifier.fitInside
permite que os apps alinhem o conteúdo às barras de sistema e mostrem
recortes. Ele pode ser usado em vez de WindowInsets
. Modifier.fitOutside
geralmente é o inverso de Modifier.fitInside
.
Por exemplo, para verificar se o conteúdo do app evita as barras de sistema e o corte
da tela, use fitInside(WindowInsetsRulers.safeDrawing.current)
.
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
A tabela a seguir mostra como o conteúdo do app ficaria com réguas predefinidas com Modifier.fitInside
ou Modifier.fitOutside
.
Tipo de régua predefinido | ||
---|---|---|
![]() |
![]() |
|
![]() |
N/A |
|
![]() |
![]() |
|
![]() |
N/A (use |
|
![]() |
![]() |
Para usar Modifier.fitInside
e Modifier.fitOutside
, é necessário restringir os
elementos combináveis. Isso significa que você precisa definir modificadores como
Modifier.size
ou Modifier.fillMaxSize
.
Algumas regras, como Modifier.fitOutside
em SafeDrawing
e SystemBars
, retornam várias regras. Nesse caso, o Android posiciona o elemento combinável usando uma régua
da esquerda, de cima, da direita ou de baixo.
Evitar o IME com Modifier.fitInside
Para processar elementos da parte de baixo com um IME com Modifier.fitInside
, transmita um
RectRuler
que usa o valor mais interno de NavigationBar
e Ime
.
@Composable fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.NavigationBars.current, WindowInsetsRulers.Ime.current ) ) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier.align(Alignment.BottomStart).fillMaxWidth() ) } }
Evitar a barra de status e a barra de legenda com Modifier.fitInside
Da mesma forma, para verificar se os elementos principais evitam a barra de status e a barra de legenda junto com Modifier.fitInsider
, transmita um RectRuler
que usa o valor mais interno de StatusBars
e CaptionBar
.
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
Criar WindowInsetsRulers
personalizado
É possível alinhar o conteúdo a réguas personalizadas. Por exemplo, considere o caso de uso em que
um elemento combinável principal processa encartes de maneira inadequada, causando problemas de padding em um
elemento filho downstream. Embora esse problema possa ser resolvido de outras maneiras, incluindo o uso de Modifier.fitInside
, também é possível criar uma régua personalizada para alinhar precisamente o elemento combinável filho sem precisar corrigir o problema no elemento pai upstream, conforme mostrado no exemplo e no vídeo a seguir:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
O vídeo a seguir mostra um exemplo de consumo problemático de encarte do IME
causado por um elemento pai upstream na imagem à esquerda e usando réguas personalizadas
para corrigir o problema à direita. Um padding extra é mostrado abaixo do TextField
Composable porque o padding da barra de navegação não foi consumido pelo elemento pai. A criança é colocada no local correto na imagem à direita usando uma régua personalizada, como mostrado no exemplo de código anterior.
Verificar se os familiares responsáveis estão restritos
Para usar WindowInsetsRulers
com segurança, confira se o elemento pai fornece restrições válidas. Os elementos pai precisam ter um tamanho definido e não podem depender do tamanho de um
elemento filho que usa WindowInsetsRulers
. Use fillMaxSize
ou outros modificadores de tamanho em elementos combináveis principais.
Da mesma forma, colocar um elemento combinável que usa WindowInsetsRulers
dentro de um contêiner de rolagem, como verticalScroll
, pode causar um comportamento inesperado, já que o contêiner de rolagem fornece restrições de altura ilimitadas, que são incompatíveis com a lógica da régua.