WindowInsets
es la API estándar en Jetpack Compose para controlar las áreas de la pantalla que están parcial o totalmente ocultas por la IU del sistema. Estas áreas incluyen la barra de estado, la barra de navegación y el teclado en pantalla. También puedes pasar WindowInsetsRulers
predefinidos, como SafeDrawing
a Modifier.fitInside
o Modifier.fitOutside
para alinear tu contenido con las barras del sistema y el corte de pantalla, o bien crear WindowInsetsRulers
personalizados.
Ventajas de WindowInsetsRulers
- Evita la complejidad del consumo: Opera durante la fase de colocación del diseño. Esto significa que omite por completo la cadena de consumo de inserciones y siempre puede proporcionar las posiciones absolutas y correctas de las barras del sistema y los cortes de pantalla, independientemente de lo que hayan hecho los diseños principales. Usar los métodos
Modifier.fitInside
oModifier.fitOutside
es útil para solucionar problemas cuando los elementosModifier.fitInside
superiores consumen de forma incorrecta las inserciones. - Evita fácilmente las barras del sistema: Ayuda al contenido de tu app a evitar las barras del sistema y el corte de pantalla, y puede ser más sencillo que usar
WindowInsets
directamente. - Altamente personalizable: Los desarrolladores pueden alinear el contenido con reglas personalizadas y tener un control preciso sobre sus diseños con diseños personalizados.
Desventajas de WindowInsetsRulers
- No se puede usar para la medición: Debido a que opera durante la fase de colocación, la información posicional que proporciona no está disponible durante la fase de medición anterior.
Alinea tu contenido con los métodos de Modifier
Modifier.fitInside
permite que las apps alineen el contenido con las barras del sistema y las muescas de pantalla. Se puede usar en lugar de WindowInsets
. Modifier.fitOutside
suele ser la inversa de Modifier.fitInside
.
Por ejemplo, para verificar que el contenido de la app evite las barras del sistema y el corte de pantalla, puedes usar fitInside(WindowInsetsRulers.safeDrawing.current)
.
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
En la siguiente tabla, se muestra cómo se vería el contenido de tu app con reglas predefinidas con Modifier.fitInside
o Modifier.fitOutside
.
Tipo de regla predefinido | ||
---|---|---|
![]() |
![]() |
|
![]() |
N/A |
|
![]() |
![]() |
|
![]() |
N/A (usa |
|
![]() |
![]() |
Para usar Modifier.fitInside
y Modifier.fitOutside
, los elementos componibles deben estar restringidos. Esto significa que debes definir modificadores como Modifier.size
o Modifier.fillMaxSize
.
Algunas reglas, como Modifier.fitOutside
en SafeDrawing
y SystemBars
, devuelven varias reglas. En este caso, Android coloca el elemento Composable con una regla desde la izquierda, la parte superior, la derecha y la parte inferior.
Evita el IME con Modifier.fitInside
Para controlar los elementos inferiores con un IME con Modifier.fitInside
, pasa un RectRuler
que tome el valor más interno de NavigationBar
y 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() ) } }
Evita la barra de estado y la barra de título con Modifier.fitInside
Del mismo modo, para verificar los elementos superiores y evitar la barra de estado y la barra de subtítulos junto con Modifier.fitInsider
, pasa un RectRuler
que tome el valor más interno de StatusBars
y CaptionBar
.
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
Crea WindowInsetsRulers
personalizados
Puedes alinear el contenido con reglas personalizadas. Por ejemplo, considera el caso de uso en el que un elemento componible principal controla de forma incorrecta las inserciones, lo que provoca problemas de padding en un elemento secundario de nivel inferior. Si bien este problema se puede resolver de otras maneras, incluso con Modifier.fitInside
, también puedes crear una regla personalizada para alinear con precisión el elemento componible secundario sin tener que corregir el problema en el elemento principal upstream, como se muestra en el siguiente ejemplo y video:
@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) } } } }
En el siguiente video, se muestra un ejemplo del consumo problemático de la inserción del IME causado por un elemento superior upstream en la imagen de la izquierda y el uso de reglas personalizadas para solucionar el problema en la imagen de la derecha. Se muestra un relleno adicional debajo del elemento TextField
Composable, ya que el elemento principal no consumió el relleno de la barra de navegación. El hijo se coloca en la ubicación correcta de la imagen derecha con una regla personalizada, como se ve en la muestra de código anterior.
Verifica que los elementos principales estén restringidos
Para usar WindowInsetsRulers
de forma segura, asegúrate de que la madre o el padre proporcione restricciones válidas. Los elementos superiores deben tener un tamaño definido y no pueden depender del tamaño de un elemento secundario que use WindowInsetsRulers
. Usa fillMaxSize
o algún otro modificador de tamaño en elementos componibles principales.
Del mismo modo, colocar un elemento componible que use WindowInsetsRulers
dentro de un contenedor de desplazamiento, como verticalScroll
, puede provocar un comportamiento inesperado, ya que el contenedor de desplazamiento proporciona restricciones de altura no delimitadas, que son incompatibles con la lógica de la regla.