I have a `FlowRow` that shows a bunch of tags (Chi...
# compose
m
I have a
FlowRow
that shows a bunch of tags (Chips). I was expecting this to be typically less than a hundred items, but I notice some users have over 500, and this causes major performance issues. How do you deal with `FlowRow`s with too many items?
s
You could show only the first ~50 items and implement a 'Show More' function. Possibly with a different layout where you can use a LazyLayout instead of a FlowRow. Maybe ContextualFlowRow helps. It's deprecated (so its more of a stopgap solution) but its documentation says its suited for large lists.
m
Yes, but the problem with using, say, a LazyColumn, is that it’s just two many items where each item is usually just a word. So it would be huge was of space especially on a large screen device. I suppose the ContextualFlowRow is the only option for now.
s
m
One idea might be to group the items according to their first letter and then show a LazyRow for each group. This would be inside a LazyColumn which should be possible because LazyRow is fixed height. But this wouldn’t be good if the tags start with numbers: “1, 10, 2, 3 etc”
s
Or I believe it should not be too hard to write a custom item placement for a LazyList layout.
m
Is there a way to stop FlowLayout laying out items below the view port?
🤷‍♂️ 1
g
hmm what kind of performance issue do you get ? Dont experience any with 500 items on my side! You sure you're not having unnecessary recompositions ?
If you're willing to take on the burden of an unmaintained component, the Compose release notes suggest that
ContextualFlowRow
can be implemented fully in userspace
just don't get coupled too closely to its implementation, since there will likely be a more polished replacement in the future
m
@Guillaume B I’m not sure actually. Scrolling is perfectly smooth. It’s just the initial layout time. Takes 2278ms to render. I don’t have any experience checking for recompositions, I’ve always relied on common sense up until now ha, and it seems to have worked for the most part! I tried adding this just before the
FlowRow
call and it usually shows
1
. Should I also be trying this with each item?
Copy code
val recompositionCount = remember { mutableIntStateOf(0) }

LaunchedEffect(Unit) {
    recompositionCount.value++
}

Text("Recompositions: ${recompositionCount.value}")
When I replace the Chip with a
Text
composable, the rendering time comes down to about 900ms. So a big improvement. Claude suggests I use this, so I’m currently playing around with it to see if I can make it look the same. Note: I need the chip to be long-clickable.
Copy code
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun FastChipText(
    label: String,
    onClick: () -> Unit,
    onLongClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Text(
        text = label,
        modifier = modifier
            .background(
                color = MaterialTheme.colorScheme.surfaceVariant,
                shape = RoundedCornerShape(percent = 50),
            )
            .padding(horizontal = 12.dp, vertical = 6.dp)
            .combinedClickable(
                onClick = onClick,
                onLongClick = onLongClick
            ),
        style = MaterialTheme.typography.labelMedium,
        color = MaterialTheme.colorScheme.onSurfaceVariant
    )
}
g
hey @Mark! indeed I also have some latency on the initial layout, you're right! (scrolling is ok). Will take a look about how to optimize that