4

Recently LazyLayout for compose was shared as experimental to try things out. It's used by other lazy implementations for list (column / row) and grid. I wanted to try this out and implement a simple custom lazy layout to consume scrolling and display items lazily (similarly to LazyList). The code below is dummy, but the idea is to do something on scrolling offset (in this example I'm placing 3 items with a space of scroll offset).

The problem is that on scroll all composables disappear with layout block being called but it doesn't place anything (only initial composition). The answer probably lies somewhere in LazyList or LazyGrid, but I wanted to avoid copy paste and do something incrementally. I'd appreciate if someone could shed some light on this issue, how to actually handle scrolling with LazyLayout.

I tried replacing scrollable with verticalScroll but it gives same results.

@OptIn(ExperimentalFoundationApi::class) @Composable fun CustomLazyLayout( modifier: Modifier = Modifier, content: @Composable (String) -> Unit ) { val scrollState = rememberScrollState() var firstId by remember { mutableStateOf(0) } var firstOffset by remember { mutableStateOf(0) } LazyLayout( modifier = modifier .clipScrollableContainer(Orientation.Vertical) .scrollable( orientation = Orientation.Vertical, reverseDirection = false, interactionSource = null, flingBehavior = ScrollableDefaults.flingBehavior(), state = scrollState, overscrollEffect = ScrollableDefaults.overscrollEffect(), enabled = true ), itemProvider = object : LazyLayoutItemProvider { override val itemCount: Int get() = 10 @Composable override fun Item(index: Int) { content("$index") } }, measurePolicy = { constraints -> val list = mutableListOf<Placeable>() var i = firstId while(i < firstId+3) { val m = measure(i, constraints) if (m.isNotEmpty()) { list.add(m[0]) } ++i } val height = list.first().measuredHeight var positionY = 0 layout(constraints.maxWidth, constraints.maxHeight) { for (placeable in list) { placeable.place(0, positionY + scrollState.value) positionY += height } } } ) 
1
  • 1
    Thanks you for sharing your LazyLayout implementation! Commented Feb 7, 2023 at 13:07

1 Answer 1

2

Problem is solved if I move scrollableState outside of layout block to measurePolicy. To be precise this code will actually mimic regular scroll effect:

 var positionY = -scrollState.value layout(constraints.maxWidth, constraints.maxHeight) { for (placeable in list) { placeable.place(0, positionY) positionY += height } } 

Previously on scroll only layout block was called. Now both are (measure and layout). I'm still quite unsure if I'm doing it the right way, but items are composed only once so I guess it's working.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.