import android.view.Gravity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
fun StaggeredFlow(
modifier: Modifier = Modifier,
itemSpacing: Dp = 0.dp,
lineSpacing: Dp = 0.dp,
gravity: Int = Gravity.LEFT,
content: @Composable () -> Unit
) {
Layout(
modifier = modifier,
content = content
) { measurables, constraints ->
var lineWidth = 0
var totalHeight = 0
var lineHeight = 0
var mAllPlaceables = mutableListOf<MutableList<Placeable>>()
// 每一行最高的高度
var mLineHeight = mutableListOf<Int>()
// 每行放置的内容
var lineViews = mutableListOf<Placeable>()
// 不要进一步限制子视图,使用给定的约束来测量它们
val placeables = measurables.mapIndexed { i, measurable ->
// 测量每个子视图
val placeable = measurable.measure(constraints)
var childWidth = placeable.width
var childHeight = placeable.height
if(lineWidth + childWidth > constraints.maxWidth){
mLineHeight.add(lineHeight)
mAllPlaceables.add(lineViews)
lineViews = mutableListOf()
lineViews.add(placeable)

totalHeight +=lineHeight
lineWidth = childWidth
lineHeight = childHeight
totalHeight += lineSpacing.toPx().toInt()
}else{
lineWidth += childWidth + if (i==0) 0 else itemSpacing.toPx().toInt()
lineHeight = maxOf(lineHeight,childHeight)
lineViews.add(placeable)
}
if(i == measurables.size - 1){
totalHeight += lineHeight
mLineHeight.add(lineHeight)
mAllPlaceables.add(lineViews)
}
}
// 设置父布局的大小,摆放子视图
layout(constraints.maxWidth, totalHeight) {
var topOffset = 0
var leftOffset = 0
for(i in mAllPlaceables.indices){
lineViews = mAllPlaceables[i]
lineHeight = mLineHeight[i]
for (j in lineViews.indices){
val child = lineViews[j]
val childWidth = child.width
val childHeight = child.height
val childTop = getItemTop(gravity,lineHeight,topOffset,childHeight)
child.placeRelative(leftOffset,childTop)
leftOffset += childWidth + lineSpacing.toPx().toInt()
}
leftOffset = 0
topOffset += lineHeight + lineSpacing.toPx().toInt()
}
}
}
}

private fun getItemTop(gravity: Int,lineHeight: Int,topOffset: Int,childHeight: Int): Int {
return when(gravity){
Gravity.CENTER -> topOffset + (lineHeight-childHeight) / 2
Gravity.BOTTOM -> topOffset + lineHeight-childHeight
else -> topOffset
}
}

使用

StaggeredFlow(
modifier = Modifier
) {

for (keyWords in userInfo.keywords ?: emptyList<KeyWords>()) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
HaiveCustomText(
text = "${keyWords.label} (${keyWords.count})",
color = HaiveColor_4A494A,
fontSize = 17.sp
)
Spacer(modifier = Modifier.size(20.dp))
}
}


}