1

As of Jetpack Compose, a Recycler type of view is called Lazy.

For now, there are only Lazy Row and Lazy Column.

I have a Staggered Grid custom Composable, that is scrollable. But is there a way I can make it Lazy? Or is such an API not stable yet?

2 Answers 2

3

You can do the same effect in many ways, one of them is:

@Composable
fun StaggeredVerticalGrid(
    modifier: Modifier = Modifier,
    maxColumnWidth: Dp,
    children: @Composable () -> Unit
) {
    Layout(
        children = children,
        modifier = modifier
    ) { measurables, constraints ->
        check(constraints.hasBoundedWidth) {
            "Unbounded width not supported"
        }
        val columns = ceil(constraints.maxWidth / maxColumnWidth.toPx()).toInt()
        val columnWidth = constraints.maxWidth / columns
        val itemConstraints = constraints.copy(maxWidth = columnWidth)
        val colHeights = IntArray(columns) { 0 } // track each column's height
        val placeables = measurables.map { measurable ->
            val column = shortestColumn(colHeights)
            val placeable = measurable.measure(itemConstraints)
            colHeights[column] += placeable.height
            placeable
        }

        val height = colHeights.maxOrNull()?.coerceIn(constraints.minHeight, constraints.maxHeight)
            ?: constraints.minHeight
        layout(
            width = constraints.maxWidth,
            height = height
        ) {
            val colY = IntArray(columns) { 0 }
            placeables.forEach { placeable ->
                val column = shortestColumn(colY)
                placeable.place(
                    x = columnWidth * column,
                    y = colY[column]
                )
                colY[column] += placeable.height
            }
        }
    }
}

private fun shortestColumn(colHeights: IntArray): Int {
    var minHeight = Int.MAX_VALUE
    var column = 0
    colHeights.forEachIndexed { index, height ->
        if (height < minHeight) {
            minHeight = height
            column = index
        }
    }
    return column
}

extracted from Owl sample app, Don't forget to wrap/call this Composable inside ScrollableColumn.

EDIT: with the release of compose 1.0.0-alpha09, now you have official LazyVerticalGrid, check release notes

Sign up to request clarification or add additional context in comments.

4 Comments

LazyVerticalGrid does not I clude a StaggeredGrid behaviour
No Problem, you can still copy-paste code snippet above it has the staggered effect and also you can customize it as you want
Yeah, only problem is, it won't be Lazy
You're right, both solutions have some caveats. you'll need to wrap/customize LazyVerticalGrid to achieve staggered effect if you want something perfect
0

If you are implementing a custom staggered grid, I would say you implement a staggered row instead. Then create another Composable that receives the data and feeds it in the staggered rows while internally using a lazy column for each row. I am not asking you to implement something new. Just tweak the existing implementation a bit and it will be a great performance boost.

Also, if your data is not big enough, it is okay to not use lazy containers.

2 Comments

What is considered big here?
Anything that causes a "lag" in the scroll. You should take the threshold from the lowest performing processor available, so that it works smoothly on all the devices. If the data is able to get displayed lag-free on athe lowest-end device, it'll work fine on every other device even without the lazy layouts. Else, you should divert to using lazy layouts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.