What You Will Build
A Pinterest-style masonry layout using LazyVerticalStaggeredGrid where items have varying heights and are arranged in two columns. Each cell displays a colored card with a label and its height value. This layout is essential for image galleries, product catalogs, and social media feeds.
Why This Pattern Matters
Unlike standard grids that enforce uniform cell heights, staggered grids let each item occupy its natural height. Compose provides LazyVerticalStaggeredGrid as a first-class API starting from Compose Foundation 1.3, eliminating the need for third-party libraries.
Step 1: Define the Grid Item
data class StaggeredItem(
val id: Int,
val height: Int,
val color: Color,
val label: String
)
Step 2: Build the Staggered Grid
@Composable
fun StaggeredGridScreen() {
val colors = listOf(
Color(0xFFEF4444), Color(0xFFF59E0B), Color(0xFF10B981),
Color(0xFF3B82F6), Color(0xFF8B5CF6), Color(0xFFEC4899),
Color(0xFF14B8A6), Color(0xFFF97316)
)
val items = remember {
(1..20).map { i ->
StaggeredItem(
id = i,
height = Random(i).nextInt(100, 250),
color = colors[i % colors.size],
label = "Item $i"
)
}
}
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalItemSpacing = 12.dp
) {
items(items, key = { it.id }) { item ->
Surface(
modifier = Modifier
.fillMaxWidth()
.height(item.height.dp),
shape = RoundedCornerShape(16.dp),
color = item.color,
shadowElevation = 4.dp
) {
Box(
modifier = Modifier.fillMaxSize().padding(16.dp),
contentAlignment = Alignment.BottomStart
) {
Column {
Text(item.label, color = Color.White,
fontWeight = FontWeight.Bold, fontSize = 18.sp)
Text("${'$'}{item.height}dp",
color = Color.White.copy(alpha = 0.7f),
fontSize = 12.sp)
}
}
}
}
}
}
Tips and Pitfalls
- StaggeredGridCells.Fixed(2) creates exactly two columns. Use
Adaptive(minSize = 150.dp)for responsive column counts. - Provide stable keys via
key = { it.id }for efficient recomposition during scrolling. - verticalItemSpacing is separate from
horizontalArrangementspacing because staggered grids manage vertical gaps per-item. - For images: Replace the colored Surface with
AsyncImagefrom Coil and useModifier.heightIn(min = 100.dp)for natural image sizing.