Is there any way to create a pinterest (waterfall)...
# compose
s
Is there any way to create a pinterest (waterfall) style layout in jetpack compose? Ideally there would be a
lazyGridFor
that could have multiple columns that don’t require even-height rows, but i’d settle for fully rendering if it’s currently possible

https://user-images.githubusercontent.com/29085/56487936-b3bc2c00-6491-11e9-8493-bb89c4f00a92.png

Actually, I see
LazyVerticalGrid
with
GridCells.Adaptive
which seems exactly what I need, but I’m not able to access it through
alpha08
. Is it not out until
alpha09
? https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:co[…]undation/lazy/LazyGrid.kt;l=88?q=LazyVerticalGrid&ss=androidx
FYI i found that compose samples has a
StaggeredVerticalGrid
component but it is a bit too rigid for my needs: https://github.com/android/compose-samples/blob/2cff65334ea023956a58f215a13b6a55c7[…]app/src/main/java/com/example/owl/ui/courses/FeaturedCourses.kt
👍 1
a
LazyVerticalGrid
will not support cells with different height. at least yet. doing staggered grids with lazy is currently untrivial. I would suggest to take a look on the implementation from samples for now
t
Not sure if it works but. What if you use the LazyColumn DSL and just draw 2 Columns with Rows inside. Will LazyColumn detect if the cells are visible or not?
But you need to know all elements and also the height of all elements so that you can calculate the layout. But you do not need to load every image
Ok no. I tried it and it is not possible to implement it efficiently without completely rework the LazyColumn code. Which is very complicated unfortunately.
s
I was able to create my desired layout by hacking
LazyColumn
which has some quirks that I can live with+adjust for:
Copy code
LazyColumn {
    item { Header("Communities")}

    itemsIndexed(communities.chunked(2)) { index, chunk ->
        Box(Modifier.padding(bottom = 30.dp)) {
            if (index == 0) {
                CreateAndExploreButtons()
            }
            Row(horizontalArrangement = Arrangement.spacedBy(30.dp)) {
                chunk.forEachIndexed { i, community ->
                    CommunityCard(
                        community = community,
                        modifier = Modifier
                            .weight(1f)
                            .height(200.dp)
                            .offset(y = if (i % 2 == 0) 0.dp else (68.dp + 30.dp)), // Shift layout of second column
                        onSelect = onSelect
                    )
                }
                if (chunk.count() == 1) {
                    // Added in case the last row only has one item
                    Spacer(Modifier.weight(1f))
                }
            }
        }
    }
}
This heavily relies on the cards being consistent dimensions, but fortunately for us that is a requirement. Lmk what you think @Timo Drick
😎 1
👍 1
t
Interesting solution. Not expected that this would work.
So you change the offset. Very interesting. Maybe it is possible to make a more general solution out of that where you have different aspect ratios
s
The biggest drawback is that when scrolling back to the top of the list, the second column cards are late to render, so they pop into view and it is a bit jarring. I think I can fix this by rendering a larger portion of the
LazyColumn
and then offset/push off the top of the screen. It would be even easier if there were the ability to configure extra buffer area so that recycled items are more aggressively rendered
t
That is not possible yet. But would be helpful also for other use cases. Maybe we could file a feature request for that.