-
-
Save austinevick/a6ccea969de27348cf92eb1ff2904233 to your computer and use it in GitHub Desktop.
Jetpack Compose simple flex-wrap container
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun FlowRow( | |
horizontalGap: Dp = 0.dp, | |
verticalGap: Dp = 0.dp, | |
alignment: Alignment.Horizontal = Alignment.Start, | |
content: @Composable () -> Unit, | |
) = Layout(content = content) { measurables, constraints -> | |
val horizontalGapPx = horizontalGap.toPx().roundToInt() | |
val verticalGapPx = verticalGap.toPx().roundToInt() | |
val rows = mutableListOf<Row>() | |
var rowConstraints = constraints | |
var rowPlaceables = mutableListOf<Placeable>() | |
measurables.forEach { measurable -> | |
val placeable = measurable.measure(Constraints()) | |
if (placeable.measuredWidth !in rowConstraints.minWidth..rowConstraints.maxWidth) { | |
rows += Row(rowPlaceables, horizontalGapPx) | |
rowConstraints = constraints | |
rowPlaceables = mutableListOf() | |
} | |
val consumedWidth = placeable.measuredWidth + horizontalGapPx | |
rowConstraints = rowConstraints.offset(horizontal = -consumedWidth) | |
rowPlaceables.add(placeable) | |
} | |
rows += Row(rowPlaceables, horizontalGapPx) | |
val width = constraints.maxWidth | |
val height = (rows.sumBy { row -> row.height } + (rows.size - 1) * verticalGapPx) | |
.coerceAtMost(constraints.maxHeight) | |
layout(width, height) { | |
var y = 0 | |
rows.forEach { row -> | |
val offset = alignment.align(row.width, width, layoutDirection) | |
var x = offset | |
row.placeables.forEach { placeable -> | |
placeable.placeRelative(x, y) | |
x += placeable.width + horizontalGapPx | |
} | |
y += row.height + verticalGapPx | |
} | |
} | |
} | |
private class Row( | |
val placeables: List<Placeable>, | |
val horizontalGapPx: Int, | |
) { | |
val width by lazy(mode = LazyThreadSafetyMode.NONE) { | |
placeables.sumBy { it.width } + (placeables.size - 1) * horizontalGapPx | |
} | |
val height by lazy(mode = LazyThreadSafetyMode.NONE) { | |
placeables.maxOfOrNull { it.height } ?: 0 | |
} | |
} | |
@Composable | |
private fun Preview(alignment: Alignment.Horizontal) { | |
Box(Modifier.width(100.dp)) { | |
FlowRow( | |
horizontalGap = 8.dp, | |
verticalGap = 8.dp, | |
alignment = alignment, | |
) { | |
repeat(17) { index -> | |
Text(text = index.toString()) | |
} | |
} | |
} | |
} | |
@Preview | |
@Composable | |
private fun PreviewAlignStart() = Preview(alignment = Alignment.Start) | |
@Preview | |
@Composable | |
private fun PreviewAlignCenter() = Preview(alignment = Alignment.CenterHorizontally) | |
@Preview | |
@Composable | |
private fun PreviewAlignEnd() = Preview(alignment = Alignment.End) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment