androidkotlinandroid-jetpack-compose

LazyVerticalStaggeredGrid last item misalignment in 2 columns


I'm using LazyVerticalStaggeredGrid in Jetpack Compose, and I have encountered an issue where the last item always ends up aligned to the right when using 2 columns, but behaves as expected (aligned to the left) when there are 3 columns.

Here's a summary of the issue:

I am not reversing the grid, and I don’t want to alter the structure of the items. I need to ensure that the last item in a 2-column grid also aligns to the left, just like it does in the 3-column grid.

You can take the following code as an example and here's a screenshot for the issue. It should be item 3 in the top and 2 in the left and 1 at the right

issue screenshot

@Composable
fun SquareGridScreen(columns: Int) {
    val gridState = rememberLazyStaggeredGridState()
    val itemsList = (1..7).toList()

    LazyVerticalStaggeredGrid(
        columns = StaggeredGridCells.Fixed(columns),
        modifier = Modifier.fillMaxSize(),
        state = gridState,
        horizontalArrangement = Arrangement.spacedBy(5.dp),
        contentPadding = PaddingValues(8.dp),
    ) {

        item(span = StaggeredGridItemSpan.FullLine) {
            Spacer(modifier = Modifier.size(20.dp))
        }

        itemsIndexed(itemsList) { index, item ->
            val itemWidth = Modifier
                .fillMaxWidth(1f / columns)
                .aspectRatio(1f)
            SquareGridItem(modifier = itemWidth)
        }
    }
}

@Composable
fun SquareGridItem(modifier: Modifier) {

    Box(
        modifier = modifier
            .padding(4.dp)
            .background(randomColor()) // Random background for demo purposes
    )
}

fun randomColor(): Color {
    return Color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))
}

Example Screenshot


Solution

  • LazyVerticalStaggeredGrid tries to fit its columns into the available width by dividing it evenly, but sometimes it is impossible. For example, 1000 can be divided evenly by 2 (500 + 500), but not by 3. In this case the first columns are slightly wider that the last ones, i.e. 334 + 333 + 333. By using .aspectRatio(1f) you make the wider items also taller which causes the described effect (on your screenshot the blue box is slightly below the box to the right of it).

    To fix the issue you have to either control LazyVerticalStaggeredGrid width to avoid uneven columns or figure out items' height independently from their width, without .aspectRatio(1f).

    Also, .fillMaxWidth(1f / columns) is unnecessary either way.