Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
@file:OptIn(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing copyright header. I think you can run './gradlew spotlessApply' to fix that and the build.

ExperimentalGridApi::class, ExperimentalMediaQueryApi::class,
ExperimentalComposeUiApi::class
)

package com.example.compose.snippets.layouts.grid

import androidx.compose.foundation.layout.ExperimentalGridApi
import androidx.compose.foundation.layout.Grid
import androidx.compose.foundation.layout.GridConfigurationScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.ComposeUiFlags
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.ExperimentalMediaQueryApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.derivedMediaQuery
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp


// [START android_compose_layout_grid_area_ids]
/**
* An enum representing the IDs for named areas within the grid.
*/
enum class GridAreaNames {
Area1,
Area2,
Area3,
Area4
}
// [END android_compose_layout_grid_area_ids]

/**
* A sample demonstrating the use of named areas in a [Grid] layout.
* This approach allows you to define the layout structure separately from the
* content, making it easier to manage and update.
*/
@Preview(showBackground = true)
@Composable
fun NamedArea() {
// [START android_compose_layout_grid_named_area]
Grid(
config = {
// Define a single column that takes all available width.
column(1f)
// 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)

gap(4.dp)
},
modifier = Modifier.size(360.dp)
) {
PastelRedCard(
"Area 1",
// Use Modifier.gridItem(areaId) to place this composable into the
// grid area defined with the matching ID in the config block.
modifier = Modifier.gridItem(areaId = GridAreaNames.Area1)
)
PastelGreenCard(
"Area 2",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area2)
)
PastelBlueCard(
"Area 3",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area3)
)
PastelYellowCard(
"Area 4",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area4)
)
}
// [END android_compose_layout_grid_named_area]
}

/**
* 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")
// [START android_compose_layout_grid_hoisted_grid_configuration]
@Composable
fun HoistedGridConfiguration() {
// [START_EXCLUDE silent]
ComposeUiFlags.isMediaQueryIntegrationEnabled = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Modifying global configuration flags like ComposeUiFlags.isMediaQueryIntegrationEnabled directly during the composition phase is a side effect. Composable functions should be free of side effects to ensure thread safety and predictable behavior. Consider wrapping this modification in a SideEffect block.

Suggested change
ComposeUiFlags.isMediaQueryIntegrationEnabled = true
androidx.compose.runtime.SideEffect {
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
}
}

FourCardsInGrid(
gridConfiguration = gridConfiguration,
modifier = Modifier.fillMaxSize()
)
}
// [END android_compose_layout_grid_hoisted_grid_configuration]


// [START android_compose_layout_grid_grid_configuration_scope]
/**
* A reusable composable that displays four colored cards in a grid.
* The layout of the cards is determined by the provided [gridConfiguration].
*/
@Composable
fun FourCardsInGrid(
gridConfiguration: GridConfigurationScope.() -> Unit,
modifier: Modifier = Modifier
) {
Comment on lines +119 to +122

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the Jetpack Compose API guidelines, the modifier parameter should be the first optional parameter of a Composable function. Additionally, placing the configuration lambda as the last parameter allows callers to use Kotlin's trailing lambda syntax.

Suggested change
fun FourCardsInGrid(
gridConfiguration: GridConfigurationScope.() -> Unit,
modifier: Modifier = Modifier
) {
fun FourCardsInGrid(
modifier: Modifier = Modifier,
gridConfiguration: GridConfigurationScope.() -> Unit
) {

Grid(
config = gridConfiguration,
modifier = modifier
) {
PastelRedCard(
"Area 1",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area1)
)
PastelGreenCard(
"Area 2",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area2)
)
PastelBlueCard(
"Area 3",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area3)
)
PastelYellowCard(
"Area 4",
modifier = Modifier.gridItem(areaId = GridAreaNames.Area4)
)
}
}
// [END android_compose_layout_grid_grid_configuration_scope]

// [START android_compose_layout_grid_two_grid_configurations]
/**
* Contains different grid configurations for the [FourCardsInGrid] layout.
*/
object FourCardsLayout {
/**
* A single-column layout where each card takes the full width and 25% height.
*/
val SingleColumn: GridConfigurationScope.() -> Unit = {
column(1f)
repeat(4) { row(0.25f) }

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)

gap(4.dp)
}

/**
* A two-column layout with varying spans for different cards.
*/
val TwoColumns: GridConfigurationScope.() -> Unit = {
repeat(2) { column(0.5f) }
repeat(4) { row(0.25f) }

area(areaId = GridAreaNames.Area1, row = 1, column = 1, rowSpan = 2, columnSpan = 2)
area(areaId = GridAreaNames.Area2, row = 3, column = 1)
area(areaId = GridAreaNames.Area3, row = 3, column = 2)
area(areaId = GridAreaNames.Area4, row = 4, column = 1, columnSpan = 2)

gap(4.dp)
}
}
// [END android_compose_layout_grid_two_grid_configurations]
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ android.enableR8.fullMode=true

# Use an AndroidX snapshot build.
# https://androidx.dev/snapshots/builds
# snapshotVersion=14793336
snapshotVersion=15446712
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ appcompat = "1.7.1"
coil = "2.7.0"
# @keep
compileSdk = "37"
compose-latest = "1.11.1"
compose-latest = "1.12.0-SNAPSHOT"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this safe to change - as in are any other teams relying on compose-latest? and when will we update or remove the snapshot version?

composeUiTooling = "1.6.1"
coreSplashscreen = "1.2.0"
coroutines = "1.10.2"
Expand Down
Loading