Created
September 17, 2020 00:30
-
-
Save cbeyls/66142cc04348d8246475b730aabef701 to your computer and use it in GitHub Desktop.
FlowLayout implementation for Jetpack Compose
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
package be.digitalia.compose.layout | |
import androidx.compose.runtime.Composable | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Layout | |
import androidx.compose.ui.Modifier | |
@Composable | |
fun FlowLayout( | |
modifier: Modifier = Modifier, | |
rowHorizontalGravity: Alignment.Horizontal = Alignment.Start, | |
childVerticalGravity: Alignment.Vertical = Alignment.Top, | |
children: @Composable () -> Unit | |
) { | |
class RowInfo(val width: Int, val height: Int, val nextChildIndex: Int) | |
Layout( | |
children = children, | |
modifier = modifier | |
) { measurables, constraints -> | |
var contentWidth = 0 | |
var contentHeight = 0 | |
var rowWidth = 0 | |
var rowHeight = 0 | |
val rows = mutableListOf<RowInfo>() | |
val maxWidth = constraints.maxWidth | |
val childConstraints = constraints.copy(minWidth = 0, minHeight = 0) | |
val placeables = measurables.mapIndexed { index, measurable -> | |
measurable.measure(childConstraints).also { placeable -> | |
val newRowWidth = rowWidth + placeable.width | |
if (newRowWidth > maxWidth) { | |
rows.add(RowInfo(width = rowWidth, height = rowHeight, nextChildIndex = index)) | |
contentWidth = maxOf(contentWidth, rowWidth) | |
contentHeight += rowHeight | |
rowWidth = placeable.width | |
rowHeight = placeable.height | |
} else { | |
rowWidth = newRowWidth | |
rowHeight = maxOf(rowHeight, placeable.height) | |
} | |
} | |
} | |
rows.add(RowInfo(width = rowWidth, height = rowHeight, nextChildIndex = measurables.size)) | |
contentWidth = maxOf(contentWidth, rowWidth) | |
contentHeight += rowHeight | |
layout( | |
width = maxOf(contentWidth, constraints.minWidth), | |
height = maxOf(contentHeight, constraints.minHeight) | |
) { | |
var childIndex = 0 | |
var y = 0 | |
rows.forEach { rowInfo -> | |
var x = rowHorizontalGravity.align(parentWidth - rowInfo.width) | |
val rowHeight = rowInfo.height | |
val nextChildIndex = rowInfo.nextChildIndex | |
while (childIndex < nextChildIndex) { | |
val placeable = placeables[childIndex] | |
placeable.placeRelative( | |
x = x, | |
y = y + childVerticalGravity.align(rowHeight - placeable.height) | |
) | |
x += placeable.width | |
childIndex++ | |
} | |
y += rowHeight | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: this was a proof-of-concept to demonstrate how easy it is to create custom Compose layouts.
In real world applications you should use
FlowRow
which is available as a stable API since Compose 1.8.0.