Repository: android/compose-samples
File: JetNews/app/src/main/java/com/example/jetnews/ui/interests/InterestsScreen.kt (Kotlin)

Code before:
            outerConstraints.maxHeight.coerceIn(0, layoutHeight)
        ) {
            // Track the y co-ord we have placed children up to
            var yPosition = topPaddingPx
            placeables.forEachIndexed { index, placeable ->
                // If there's only one column, then place items one after the other
                if (columns == 1) {
                    // Position item on the screen
                    placeable.placeRelative(x = 0, y = yPosition)
                    // Increment the y co-ord with the item's height
                    yPosition += placeable.height
                } else {
                    // If there are multiple columns, then place items relative to each other
                    if (index % columns == 0) {
                        // Position item on a new row
                        placeable.placeRelative(x = 0, y = yPosition)
                    } else {
                        // Place element in the same row, the previous item exists at this point
                        val previousPlaceable = placeables[index - 1]
                        placeable.placeRelative(
                            x = previousPlaceable.width + itemSpacingPx,
                            y = yPosition
                        )

                        // Increment the y co-ord with the item's height
                        yPosition += rowHeights[index.floorDiv(columns)]
                    }
                }
            }
        }
    }
}

@Preview("Interests screen", "Interests")
@Preview("Interests screen (dark)", "Interests", uiMode = UI_MODE_NIGHT_YES)
@Preview("Interests screen (big font)", "Interests", fontScale = 1.5f)
@Composable
fun PreviewInterestsScreenDrawer() {
    JetnewsTheme {
        val tabContent = getFakeTabsContent()
        val (currentSection, updateSection) = rememberSaveable {
            mutableStateOf(tabContent.first().section)
        }

        InterestsScreen(
            tabContent = tabContent,
            currentSection = currentSection,
            isTabRowExpanded = true,
            isDrawerActive = true,
            onTabChange = updateSection,
            openDrawer = { },

Review comment (suggestion):
For a general number of columns, we should only be incrementing the `yPosition` when `index + 1 % columns == 0` (in other words, this is the last item in the row).

This works for 2 columns, since we only visit the `else` once for each row, but it wouldn't for 3 or more columns.

Code after:
        val placeables = measurables.mapIndexed { index, measureable ->
            val placeable = measureable.measure(itemConstraints)
            // Update the height for each row
            val row = index.floorDiv(columns)
            rowHeights[row] = max(rowHeights[row], placeable.height)
            placeable
        }

        // Calculate maxHeight of the Interests layout. Heights of the row + top padding
        val layoutHeight = topPaddingPx + rowHeights.sum()
        // Calculate maxWidth of the Interests layout
        val layoutWidth = itemWidth * columns + (itemSpacingPx * (columns - 1))

        // Lay out given the max width and height
        layout(
            width = outerConstraints.constrainWidth(layoutWidth),
            height = outerConstraints.constrainHeight(layoutHeight)
        ) {
            // Track the y co-ord we have placed children up to
            var yPosition = topPaddingPx
            // Split placeables in lists that don't exceed the number of columns
            // and place them taking into account their width and spacing
            placeables.chunked(columns).forEachIndexed { rowIndex, row ->
                var xPosition = 0
                row.forEach { placeable ->
                    placeable.placeRelative(x = xPosition, y = yPosition)
                    xPosition += placeable.width + itemSpacingPx
                }
                yPosition += rowHeights[rowIndex]
            }
        }
    }
}

@Preview("Interests screen", "Interests")
@Preview("Interests screen (dark)", "Interests", uiMode = UI_MODE_NIGHT_YES)
@Preview("Interests screen (big font)", "Interests", fontScale = 1.5f)
@Composable
fun PreviewInterestsScreenDrawer() {
    JetnewsTheme {
        val tabContent = getFakeTabsContent()
        val (currentSection, updateSection) = rememberSaveable {
            mutableStateOf(tabContent.first().section)
        }

        InterestsScreen(
            tabContent = tabContent,
            currentSection = currentSection,
            isExpandedScreen = false,
            onTabChange = updateSection,
            openDrawer = { },