Jetpack Compose:检测子项溢出并添加更多徽章

Jetpack Compose: Detect child item overflow and add more badge

目标

我想尽可能多地装上可用的物品 space 并在末尾添加“+{num}”徽章以指示是否还有剩余物品。类似于下图。

问题

由于事先不知道物品的数量和大小(即本例中的筹码)以及可用的 space,因此很难确切知道可以容纳多少筹码。此外,compose 仅​​对子项进行一次测量并立即进行布局。

我试过的

我尝试了以下方法,但还不够。

@Composable
fun MainScreen() {
    Column {

        val states = arrayOf(
            "NY", "CA", "NV", "PA", "AZ", "AK", "NE", "CT", "CO", "FL", "IL", "KS", "WA"
        )

        var chipCount by remember { mutableStateOf(0) }

        Row(
            modifier = Modifier
                .padding(horizontal = 16.dp)
                .wrapContentHeight(),
            verticalAlignment = Alignment.CenterVertically
        ) {

            ChipRow(
                modifier = Modifier
                    .padding(end = 4.dp)
                    .weight(1f, fill = false),
                onPlacementComplete = { chipCount = it }
            ) {
                for (state in states) {
                    Chip(
                        modifier = Modifier
                            .padding(4.dp)
                            .wrapContentSize(), text = state
                    )
                }
            }

            Text(text = "+${states.size - chipCount}", style = MaterialTheme.typography.h6)
        }
    }
}

@Composable
fun Chip(
    text: String,
    modifier: Modifier = Modifier
) {
    Surface(
        color = Color.LightGray,
        shape = CircleShape,
        modifier = modifier
    ) {
        Text(
            text = text,
            textAlign = TextAlign.Center,
            style = MaterialTheme.typography.body1,
            modifier = Modifier.padding(6.dp)
        )
    }
}

@Composable
fun ChipRow(
    modifier: Modifier = Modifier,
    onPlacementComplete: (Int) -> Unit,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->

        val placeables = measurables.map { it.measure(constraints) };

        var counter = 0

        layout(constraints.maxWidth, constraints.maxHeight) {
            var xPosition = 0
            for (placeable in placeables) {
                if (xPosition + placeable.width > constraints.maxWidth) break
                placeable.placeRelative(x = xPosition, 0)
                xPosition += placeable.width
                counter++
            }
            onPlacementComplete(counter)
        }
    }
}

首先,它看起来很老套,而不是一个合法的解决方案。其次,它没有按预期工作。输出如下。

请求

我浏览了自定义布局的官方指南并进行了多次 google 搜索。但想不出更好的办法。你能帮忙解决这种情况吗?参考链接、指向错误等,不胜感激。

提前致谢!

我也不太确定,但我认为您需要先说明列宽和行宽,使其居中。

而且我认为你不需要 1f 的体重,我相信 0.8f 会更好。

Column (
     modifier = Modifier.fillMaxWidth()
){

        val states = arrayOf(
            "NY", "CA", "NV", "PA", "AZ", "AK", "NE", "CT", "CO", "FL", "IL", "KS", "WA"
        )

        var chipCount by remember { mutableStateOf(0) }

        Row(
            modifier = Modifier
                .padding(horizontal = 16.dp)
                .wrapContentHeight()
                .modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {

            ChipRow(
                modifier = Modifier
                    .padding(end = 4.dp)
                    .weight(0.8f, fill = false),
                onPlacementComplete = { chipCount = it }
            ) {
                for (state in states) {
                    Chip(
                        modifier = Modifier
                            .padding(4.dp)
                            .wrapContentSize(), text = state
                    )
                }
            }

            Text(text = "+${states.size - chipCount}", style = MaterialTheme.typography.h6)
        }
    }

或者我希望您改用 constraintlayout。 here

您已经超过了最大约束值 (layout(constraints.maxWidth, constraints.maxHeight)),这就是您的视图占满整个屏幕的原因。

您需要传递所需的视图大小,例如:

data class Item(val placeable: Placeable, val xPosition: Int)

val items = mutableListOf<Item>()
var xPosition = 0
for (placeable in placeables) {
    if (xPosition + placeable.width > constraints.maxWidth) break
    items.add(Item(placeable, xPosition))
    xPosition += placeable.width
}

layout(
    width = items.last().let { it.xPosition + it.placeable.width },
    height = items.maxOf { it.placeable.height }
) {
    items.forEach {
        it.placeable.place(it.xPosition, 0)
    }
    onPlacementComplete(items.count())
}

结果: