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())
}
结果:
目标
我想尽可能多地装上可用的物品 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())
}
结果: