https://kotlinlang.org logo
#compose
Title
# compose
j

Justin Yue

09/04/2021, 4:38 AM
I have a similar issue found in this thread where I am inserting a
LazyVerticalGrid
inside a
Column
with a scroll state, so I now know that I can't nest composables scrolling in the same direction. However, I'm only using
LazyVerticalGrid
since the cells can be adaptive, and I don't need its scroll functionality. Is there a way to create a composable that can replicate `LazyVerticalGrid`'s adaptive functionality and removing the scrolling?
a

Albert Chang

09/04/2021, 7:43 AM
What do you mean by "adaptive"? I think you can easily create a grid layout by using multiple `Row`s and setting
Modifier.weight(1f)
on each cell.
☝🏻 1
z

Zach Klippenstein (he/him) [MOD]

09/04/2021, 1:54 PM
Yea, the only interesting part of lazy lists’ functionality is related to scrolling. The non-lazy versions of those layouts are more trivial.
j

Justin Yue

09/05/2021, 3:07 AM
Given a dp size, I think
LazyVerticalGrid
can determine how many columns and rows to create for a list of composables while meeting that minimum dp size, and I wanted to replicate that. I honestly forgot that I can create custom layouts, so I ended up going that route today. My solution is not perfect, but I'll keep working on it and am open to feedback.
Copy code
// Inspired by:
// <https://github.com/android/compose-samples/blob/main/Jetsnack/app/src/main/java/com/example/jetsnack/ui/components/Grid.kt>
@Composable
fun VerticalGrid(
    minWidth: Dp,
    rowPadding: Dp = 0.dp,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier
    ) { measurables, constraints ->
        val numOfColumns = constraints.maxWidth / minWidth.roundToPx()
        val columnWidth = constraints.maxWidth / numOfColumns

        Log.i(TAG, "numOfColumns: $numOfColumns, maxWidth: ${constraints.maxWidth} columnWidth: $columnWidth")

        val itemConstraints = constraints.copy(
            minWidth = minWidth.value.toInt(),
            maxWidth = columnWidth
        )

        val placeables = measurables.map { measurable -> measurable.measure(itemConstraints) }
        val columnHeights = Array(placeables.size) { i -> (i / numOfColumns) * 96.dp.roundToPx() + (rowPadding.roundToPx() * (i/numOfColumns))}

        for (i in columnHeights.indices) {
            Log.d(TAG, "columnHeights index $i - ${columnHeights[i]}")
        }

        var height = (columnHeights.maxOrNull() ?: constraints.minHeight )
            .coerceAtMost(constraints.maxHeight)

        Log.d(TAG, "before: $height")
        if (height < constraints.maxHeight) {
            Log.d(TAG, "num of rows: ${columnHeights.lastIndex/numOfColumns}")
            height *= (columnHeights.lastIndex/numOfColumns)
        }
        Log.d(TAG, "after: $height vs max height: ${constraints.maxHeight}")

        layout(constraints.maxWidth, (height * 0.85).toInt()) {
            placeables.forEachIndexed { index, placeable ->
                val row = index / numOfColumns
                val column = index % numOfColumns

                Log.i(TAG, "row: $row")

                placeable.placeRelative(
                    x = column * columnWidth,
                    y = columnHeights[index]
                )
            }
        }
    }
}
2 Views