Learning Android Development

StaggeredVerticalGrid of Android Jetpack Compose

Using Jetpack Compose Layout to make StaggeredVerificatlGrid

Elye
Elye
Dec 17, 2020 · 4 min read
Image for post
Image for post
Photo by Julian Hochgesang on Unsplash

Jetpack Compose, even though we have LazyColumnFor to do what RecyclerView has, but there’s not readily available StagerredGridLayout provided.

Fortunately, Google provided a sample of how this can be implemented as per this StackOverflow shared.

With that, I used to randomly generate some stagged cards and explore how it is done.

Image for post
Image for post

Using StaggeredVerticalGrid

To use it, it is simple. Just provide the maxColumnWidth for the items (e.g. Card) and then provide the item (e.g. Card) accordingly.

StaggeredVerticalGrid(
maxColumnWidth = columnWidth.value.dp,
modifier = Modifier.padding(4.dp)
) {
(1..100).forEach {
Card(it.toString(), columnWidth)
}
}

In my example, I generate a random maxColumnWidth so we can get different column count when I regenerate them. I also provide 100 Cards, that randomly generate the color and height, to make the staggering view nicer.

Understand how Staggered is done

I have modified the original StaggeredVerticalGrid to be more compute efficient by storing the initial computer locations, but overall they are very similar to the original algorithm.

It is using the Layout composable function.

@Composable
fun StaggeredVerticalGrid(
modifier: Modifier = Modifier,
maxColumnWidth: Dp,
content: @Composable () -> Unit
) {
Layout(
content = content,
modifier = modifier
) { measurables, constraints ->
// The algorithm generate staggered vertical grid
}
}

The algorithm is broken into 4 parts.

1. Calculate the right width for the columns

val columns = 
ceil(constraints.maxWidth / maxColumnWidth.toPx()).toInt()
val columnWidth = constraints.maxWidth / columns
val itemConstraints = constraints.copy(maxWidth = columnWidth)

Given the maxColumnWidth, the algorithm will first calculate the with it can stretch the most for each of the items.

Image for post
Image for post
  1. Calculate the total columns possible using maxWidth divided by the maxColumnWidth
  2. From the column counts, when we can get the exact width that can be allocated to each item without violating the maxColumnWidth
  3. Then copy all the constraint over, with only modifying the maxWidth for each item.

2. Compute the total height of the layout

val colHeights = IntArray(columns) { 0 } 
val placeables = measurables.map { measurable ->
val column = shortestColumn(colHeights)
val placeable = measurable.measure(itemConstraints)
placeableXY[placeable]
= Pair(columnWidth * column, colHeights[column])
colHeights[column] += placeable.height
placeable
}

For each of the measurable (e.g. Card), we’ll try to place the column that is the shortest height.

From the measurable, we’ll get the exact item i.e. placeable to get the height of it to be added to colHeight.

The colHeight is used to keep track of the height of each column, so that we can place the placeable into the shortest column area, and also we can get the final height needed for the layout.

Image for post
Image for post

As shown in above the diagram, you’ll notice each placeable is always placed at the shortest column first.

3. Get the height of the layout

And finally the longest height ie. colHeight[0] is used to determined the layout height.

val height = colHeights.maxOrNull()
?.coerceIn(constraints.minHeight, constraints.maxHeight)
?: constraints.minHeight
Image for post
Image for post
Notice the layout is represented in yellow color

4. Place all the peaceable (i.e. card) in the layout

Lastly, after the layout size is determined, we can then place each of the cards accordingly to the X, Y location that was previously stored in placeableXY.

layout(
width = constraints.maxWidth,
height = height
) {
placeables.forEach { placeable ->
placeable.place(
x = placeableXY.getValue(placeable).first,
y = placeableXY.getValue(placeable).second
)
}
}
Image for post
Image for post

That’s it. Now not only you know how to use StaggeredVerticalGrid, but also how to use Layout and make it works for you better.

You can get the code here. Cheers.

Mobile App Development Publication

Sharing Mobile App Development and Learning

Elye

Written by

Elye

Passionate about learning, and sharing mobile development and others https://twitter.com/elye_project https://www.facebook.com/elye.proj

Mobile App Development Publication

Sharing iOS, Android and relevant Mobile App Development Technology and Learning

Elye

Written by

Elye

Passionate about learning, and sharing mobile development and others https://twitter.com/elye_project https://www.facebook.com/elye.proj

Mobile App Development Publication

Sharing iOS, Android and relevant Mobile App Development Technology and Learning

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store