Issue
There is requirements to create ChipGroup with maximum lines/rows allowed, for all items that are not shown there should be last chip with text like "+3 more items".
I have tried FlowRow
from accompanist, which works fine, but number of rows cannot be limited there (or I don't know how to :))
Another option I have tried is to implement custom layout. I have managed to limit number of rows (implementation similar to FlowRow
with additional conditions), but I'm not sure how to append last item from layout(...placementBlock: Placeable.PlacementScope.() -> Unit)
Any help is appreciated
Solution
In such cases SubcomposeLayout
should be used: it allows you to insert a composable depending on already measured views.
Applying this to FlowRow
would take more time, because of many other arguments, so I've took my own simplified variant as the base.
@Composable
fun ChipVerticalGrid(
modifier: Modifier = Modifier,
spacing: Dp,
moreItemsView: @Composable (Int) -> Unit,
content: @Composable () -> Unit,
) {
SubcomposeLayout(
modifier = modifier
) { constraints ->
val contentConstraints = constraints.copy(minWidth = 0, minHeight = 0)
var currentRow = 0
var currentOrigin = IntOffset.Zero
val spacingValue = spacing.toPx().toInt()
val mainMeasurables = subcompose("content", content)
val placeables = mutableListOf<Pair<Placeable, IntOffset>>()
for (i in mainMeasurables.indices) {
val measurable = mainMeasurables[i]
val placeable = measurable.measure(contentConstraints)
fun Placeable.didOverflowWidth() =
currentOrigin.x > 0f && currentOrigin.x + width > contentConstraints.maxWidth
if (placeable.didOverflowWidth()) {
currentRow += 1
val nextRowOffset = currentOrigin.y + placeable.height + spacingValue
if (nextRowOffset + placeable.height > contentConstraints.maxHeight) {
var morePlaceable: Placeable
do {
val itemsLeft = mainMeasurables.count() - placeables.count()
morePlaceable = subcompose(itemsLeft) {
moreItemsView(itemsLeft)
}[0].measure(contentConstraints)
val didOverflowWidth = morePlaceable.didOverflowWidth()
if (didOverflowWidth) {
val removed = placeables.removeLast()
currentOrigin = removed.second
}
} while (didOverflowWidth)
placeables.add(morePlaceable to currentOrigin)
break
}
currentOrigin = currentOrigin.copy(x = 0, y = nextRowOffset)
}
placeables.add(placeable to currentOrigin)
currentOrigin = currentOrigin.copy(x = currentOrigin.x + placeable.width + spacingValue)
}
layout(
width = maxOf(constraints.minWidth, placeables.maxOfOrNull { it.first.width + it.second.x } ?: 0),
height = maxOf(constraints.minHeight, placeables.lastOrNull()?.run { first.height + second.y } ?: 0),
) {
placeables.forEach {
val (placeable, origin) = it
placeable.place(origin.x, origin.y)
}
}
}
}
Usage:
val words = LoremIpsum().values.first().split(" ").map { it.filter { it.isLetter()} }
val itemView = @Composable { text: String ->
Text(
text,
modifier = Modifier
.background(color = Color.Gray, shape = CircleShape)
.padding(vertical = 3.dp, horizontal = 5.dp)
)
}
ChipVerticalGrid(
spacing = 7.dp,
moreItemsView = {
itemView("$it more items")
},
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.padding(7.dp)
) {
words.forEach { word ->
itemView(word)
}
}
Result:
Answered By - Phil Dukhov
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.