From 9c3ba46a87472316be7d389e0e1024cc047bb26d Mon Sep 17 00:00:00 2001 From: ashnohe Date: Mon, 8 Sep 2025 15:18:12 -0700 Subject: [PATCH 1/4] add WindowInsetsRulers snippet --- .../snippets/layouts/InsetsSnippets.kt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt index 77568686d..0f2d7d963 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt @@ -28,9 +28,12 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding @@ -44,10 +47,16 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LargeTopAppBar import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextField import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment.Companion.BottomCenter import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.WindowInsetsRulers +import androidx.compose.ui.layout.layout import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.dp +import kotlin.math.roundToInt class InsetSnippetActivity : ComponentActivity() { @@ -147,3 +156,56 @@ fun OverrideDefaultInsetsSnippet() { ) // [END android_compose_insets_override_defaults] } + +// [START android_compose_insets_rulers] +@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) + } + } + } +} +// [END android_compose_insets_rulers] \ No newline at end of file From a49eb6c652ba54b4f44ddd50f592a518bff262f9 Mon Sep 17 00:00:00 2001 From: ashnohe <83780687+ashnohe@users.noreply.github.com> Date: Mon, 8 Sep 2025 22:24:36 +0000 Subject: [PATCH 2/4] Apply Spotless --- .../compose/snippets/layouts/InsetsSnippets.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt index 0f2d7d963..031d78dfb 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt @@ -159,12 +159,11 @@ fun OverrideDefaultInsetsSnippet() { // [START android_compose_insets_rulers] @Composable -fun WindowInsetsRulersDemo(modifier: Modifier){ +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. @@ -178,8 +177,8 @@ fun WindowInsetsRulersDemo(modifier: Modifier){ // Composable without having to fix the parent upstream. .alignToSafeDrawing() - //.imePadding() - //.fillMaxWidth() + // .imePadding() + // .fillMaxWidth() ) } } @@ -190,7 +189,7 @@ fun Modifier.alignToSafeDrawing(): Modifier { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height - layout(width, height){ + layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right @@ -208,4 +207,4 @@ fun Modifier.alignToSafeDrawing(): Modifier { } } } -// [END android_compose_insets_rulers] \ No newline at end of file +// [END android_compose_insets_rulers] From 6577fb6a818c322a0284e73f285ee380956f562b Mon Sep 17 00:00:00 2001 From: ashnohe Date: Mon, 15 Sep 2025 17:06:41 -0700 Subject: [PATCH 3/4] Add basic WindowInsetsRulers use cases --- .../snippets/layouts/InsetsSnippets.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt index 031d78dfb..3d8ef9c33 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt @@ -31,6 +31,8 @@ import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.fitInside import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.navigationBars @@ -49,9 +51,12 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.BottomCenter import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.RectRulers import androidx.compose.ui.layout.WindowInsetsRulers +import androidx.compose.ui.layout.innermostOf import androidx.compose.ui.layout.layout import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Constraints @@ -208,3 +213,49 @@ fun Modifier.alignToSafeDrawing(): Modifier { } } // [END android_compose_insets_rulers] + +// [START android_compose_insets_fit_inside] +@Composable +fun FitInsideDemo(modifier: Modifier) { + Box( + modifier = modifier + .fillMaxSize() + // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... + .fitInside(WindowInsetsRulers.SafeDrawing.current) + ) +} +// [END android_compose_insets_fit_inside] + +// [START android_compose_insets_rulers_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() + ) + } +} +// [END android_compose_insets_rulers_ime] + +// [START android_compose_insets_rulers_status_caption_bars] +@Composable +fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { + Box( + modifier = modifier + .fillMaxSize() + .fitInside(RectRulers.innermostOf( + WindowInsetsRulers.StatusBars.current, + WindowInsetsRulers.CaptionBar.current + )) + ) +} +// [END android_compose_insets_rulers_status_caption_bars] \ No newline at end of file From cd8564708bfa0e68c63a0bd953abcdaa02749282 Mon Sep 17 00:00:00 2001 From: ashnohe <83780687+ashnohe@users.noreply.github.com> Date: Tue, 16 Sep 2025 00:27:24 +0000 Subject: [PATCH 4/4] Apply Spotless --- .../snippets/layouts/InsetsSnippets.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt index 2cb78f6a1..e893e8099 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/InsetsSnippets.kt @@ -232,10 +232,12 @@ fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() - .fitInside(RectRulers.innermostOf( - WindowInsetsRulers.NavigationBars.current, - WindowInsetsRulers.Ime.current - )) + .fitInside( + RectRulers.innermostOf( + WindowInsetsRulers.NavigationBars.current, + WindowInsetsRulers.Ime.current + ) + ) ) { TextField( value = "Demo IME Insets", @@ -252,10 +254,12 @@ fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() - .fitInside(RectRulers.innermostOf( - WindowInsetsRulers.StatusBars.current, - WindowInsetsRulers.CaptionBar.current - )) + .fitInside( + RectRulers.innermostOf( + WindowInsetsRulers.StatusBars.current, + WindowInsetsRulers.CaptionBar.current + ) + ) ) } // [END android_compose_insets_rulers_status_caption_bars]