From e6974ac9f888ca4b942d87ac8488229d177e055e Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Wed, 15 Jul 2026 07:45:08 +0900 Subject: [PATCH 1/3] Add WideClassicCard snippet and fix preview rendering --- .../snippets/layouts/grid/GridTrackSize.kt | 6 +- .../snippets/layouts/grid/NamedArea.kt | 205 ++++++++++++++++-- 2 files changed, 189 insertions(+), 22 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/GridTrackSize.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/GridTrackSize.kt index 68c3a4219..c65b283a9 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/GridTrackSize.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/GridTrackSize.kt @@ -26,10 +26,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -190,7 +188,7 @@ fun GridTrackSizeMinMax() { // [END android_compose_layout_grid_track_size_min_max] } -@Preview(showBackground = true) +@Preview(showBackground = true, heightDp = 220) @Composable fun LazyColumnInGrid() { // [START android_compose_layout_grid_lazy_column_in_grid] @@ -206,7 +204,7 @@ fun LazyColumnInGrid() { }, modifier = Modifier.size(width = 170.dp, height = 240.dp) ) { - Text("Lazy column in a Grid") + Text("LazyColumn in a Grid") // The LazyColumn is placed in the second row, filling the remaining space. LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) { items(100) { number -> diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt index 36d1abfbc..8567b2c5a 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt @@ -21,19 +21,34 @@ package com.example.compose.snippets.layouts.grid +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ExperimentalGridApi import androidx.compose.foundation.layout.Grid import androidx.compose.foundation.layout.GridConfigurationScope +import androidx.compose.foundation.layout.GridTrackSize +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.ComposeUiFlags import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalMediaQueryApi +import androidx.compose.ui.LocalUiMediaScope import androidx.compose.ui.Modifier +import androidx.compose.ui.UiMediaScope import androidx.compose.ui.derivedMediaQuery +import androidx.compose.ui.platform.LocalWindowInfo import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -61,16 +76,17 @@ fun NamedArea() { Grid( config = { // Define a single column that takes all available width. - column(1f) + repeat(2) { column(0.5f) } + // Define four rows, each taking 25% of the total height. repeat(4) { row(0.25f) } // Define named grid areas by associating an areaId with specific row and column indices. // Row and column indices are 1-based. - area(areaId = GridAreaNames.Area1, row = 1, column = 1) - area(areaId = GridAreaNames.Area2, row = 2, column = 1) - area(areaId = GridAreaNames.Area3, row = 3, column = 1) - area(areaId = GridAreaNames.Area4, row = 4, column = 1) + area(areaId = GridAreaNames.Area1, row = 1, column = 1, columnSpan = 2) + area(areaId = GridAreaNames.Area2, row = 2, column = 1, rowSpan = 3) + area(areaId = GridAreaNames.Area3, rows = 2..3, columns = 2..2) + area(areaId = GridAreaNames.Area4, row = 4, column = 2) gap(4.dp) }, @@ -102,26 +118,30 @@ fun NamedArea() { * Demonstrates a responsive grid where the configuration is hoisted and * selected based on the window size using media queries. */ -@Preview(showBackground = true, widthDp = 240, heightDp = 240, name = "240.dp") @Preview(showBackground = true, widthDp = 120, heightDp = 240, name = "120.dp") +@Preview(showBackground = true, widthDp = 240, heightDp = 240, name = "240.dp") // [START android_compose_layout_grid_hoisted_grid_configuration] @Composable fun HoistedGridConfiguration() { // [START_EXCLUDE silent] ComposeUiFlags.isMediaQueryIntegrationEnabled = true - // [END_EXCLUDE] - // Select the appropriate grid configuration based on the window width. - val gridConfiguration by derivedMediaQuery { - when { - windowWidth < 240.dp -> FourCardsLayout.SingleColumn - else -> FourCardsLayout.TwoColumns + PreviewMediaQuery { + // [END_EXCLUDE] + // Select the appropriate grid configuration based on the window width. + val gridConfiguration by derivedMediaQuery { + when { + windowWidth < 240.dp -> FourCardsLayout.SingleColumn + else -> FourCardsLayout.TwoColumns + } } - } - FourCardsInGrid( - gridConfiguration = gridConfiguration, - modifier = Modifier.fillMaxSize() - ) + FourCardsInGrid( + gridConfiguration = gridConfiguration, + modifier = Modifier.fillMaxSize() + ) + // [START_EXCLUDE silent] + } + // [END_EXCLUDE] } // [END android_compose_layout_grid_hoisted_grid_configuration] @@ -195,4 +215,153 @@ object FourCardsLayout { gap(4.dp) } } -// [END android_compose_layout_grid_two_grid_configurations] \ No newline at end of file +// [END android_compose_layout_grid_two_grid_configurations] + +// [START android_compose_layout_grid_area_ids] +enum class CardArea { + Image, + Title, + Subtitle, + Description, + ExtraText, +} +// [END android_compose_layout_grid_area_ids] + +@Composable +private fun WideClassicCardGridConfig() { + // [START android_compose_layout_grid_wide_classic_card_grid_config] + Grid( + config = { + // Define columns: left column for image, right for content + column(GridTrackSize.Auto) + column(minmax(0.dp, 1.fr)) + + // Define row tracks for the vertical content stack + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + + // Map semantic identifiers to grid coordinates and spans + area(CardArea.Image, row = 1, column = 1, rowSpan = 4) + area(CardArea.Title, row = 1, column = 2) + area(CardArea.Subtitle, row = 2, column = 2) + area(CardArea.Description, row = 3, column = 2) + area(CardArea.ExtraText, row = 4, column = 2) + + gap(row = 8.dp, column = 16.dp) + } + ) { + // Child elements placed in Step 3 + } + // [END android_compose_layout_grid_wide_classic_card_grid_config] +} + +// [START android_compose_layout_grid_wide_classic_card] +@Composable +fun WideClassicCard( + imageContent: @Composable () -> Unit, + title: String, + subtitle: String, + description: String, + extraText: String, + modifier: Modifier = Modifier, +) { + Card(modifier = modifier) { + Grid( + config = { + // Define columns: left column for image, right for content + column(GridTrackSize.Auto) + column(minmax(0.dp, 1.fr)) + + // Define row tracks for the vertical content stack + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + row(GridTrackSize.Auto) + + // Map semantic identifiers to grid coordinates and spans + area(CardArea.Image, row = 1, column = 1, rowSpan = 4) + area(CardArea.Title, row = 1, column = 2) + area(CardArea.Subtitle, row = 2, column = 2) + area(CardArea.Description, row = 3, column = 2) + area(CardArea.ExtraText, row = 4, column = 2) + + gap(row = 8.dp, column = 16.dp) + }, + ) { + Box(modifier = Modifier.gridItem(CardArea.Image)) { + imageContent() + } + + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.gridItem(CardArea.Title), + ) + + Text( + text = subtitle, + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.gridItem(CardArea.Subtitle), + ) + + Text( + text = description, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.gridItem(CardArea.Description), + ) + + Text( + text = extraText, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.gridItem(CardArea.ExtraText), + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun WideClassicCardPreview() { + WideClassicCard( + imageContent = { + Box( + modifier = Modifier + .width(120.dp) + .fillMaxHeight() + .background(MaterialTheme.colorScheme.primaryContainer) + ) + }, + title = "Title", + subtitle = "Subtitle", + description = "This is a description of the card. It explains what the card is about in more detail.", + extraText = "Extra text", + modifier = Modifier.padding(16.dp) + ) +} + +/** + * A helper composable to provide a default [UiMediaScope] for previews. + */ +@Composable +private fun PreviewMediaQuery(content: @Composable () -> Unit) { + ComposeUiFlags.isMediaQueryIntegrationEnabled = true + val windowInfo = LocalWindowInfo.current + val uiMediaScope = remember(windowInfo) { + object : UiMediaScope { + override val windowWidth: Dp = windowInfo.containerDpSize.width + override val windowHeight: Dp = windowInfo.containerDpSize.height + override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Flat + override val viewingDistance: UiMediaScope.ViewingDistance = + UiMediaScope.ViewingDistance.Medium + override val hasMicrophone: Boolean = true + override val hasCamera: Boolean = true + override val pointerPrecision: UiMediaScope.PointerPrecision = + UiMediaScope.PointerPrecision.Coarse + override val keyboardKind: UiMediaScope.KeyboardKind = UiMediaScope.KeyboardKind.None + } + } + CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope, content = content) +} + From a63dd2b4ac5f7d364aee6214d2824e2cd255ed6d Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Wed, 15 Jul 2026 08:04:33 +0900 Subject: [PATCH 2/3] Fix snippet-bot issue --- .../java/com/example/compose/snippets/layouts/grid/NamedArea.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt index 8567b2c5a..938a23d89 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt @@ -320,6 +320,7 @@ fun WideClassicCard( } } } +// [END android_compose_layout_grid_wide_classic_card] @Preview(showBackground = true) @Composable From 143c40f775036125a9bb34bc05aad615a9959754 Mon Sep 17 00:00:00 2001 From: Chiko Shimizu Date: Wed, 15 Jul 2026 08:15:41 +0900 Subject: [PATCH 3/3] Apply padding to the text elements of the WideClassicCard --- .../compose/snippets/layouts/grid/NamedArea.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt index 938a23d89..5c50bddd2 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/layouts/grid/NamedArea.kt @@ -293,29 +293,36 @@ fun WideClassicCard( Box(modifier = Modifier.gridItem(CardArea.Image)) { imageContent() } - Text( text = title, style = MaterialTheme.typography.titleLarge, - modifier = Modifier.gridItem(CardArea.Title), + modifier = Modifier + .gridItem(CardArea.Title) + .padding(top = 16.dp, end = 16.dp), ) Text( text = subtitle, style = MaterialTheme.typography.titleMedium, - modifier = Modifier.gridItem(CardArea.Subtitle), + modifier = Modifier + .gridItem(CardArea.Subtitle) + .padding(end = 16.dp), ) Text( text = description, style = MaterialTheme.typography.bodyMedium, - modifier = Modifier.gridItem(CardArea.Description), + modifier = Modifier + .gridItem(CardArea.Description) + .padding(end = 16.dp), ) Text( text = extraText, style = MaterialTheme.typography.labelSmall, - modifier = Modifier.gridItem(CardArea.ExtraText), + modifier = Modifier + .gridItem(CardArea.ExtraText) + .padding(bottom = 16.dp, end = 16.dp), ) } }