Skip to content

LazyScrollContainerContent #67

@aliencodingjava

Description

@aliencodingjava

more info for settings here

https://github.com/nanihadesuka/LazyColumnScrollbar

**Kyant — love the demo and your library. One small note that might help people who copy/paste it.

In the demo below:**

LazyColumn(
    Modifier.fillMaxSize(),
    contentPadding = PaddingValues(16.dp),
    verticalArrangement = Arrangement.spacedBy(16.dp)
) {
    item { Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars)) }
    items(100) {
        Box(
            Modifier
                .drawBackdrop(
                    backdrop = backdrop,
                    shape = { ContinuousRoundedRectangle(32.dp) },
                    effects = {
                        vibrancy()
                        lens(16.dp.toPx(), 32.dp.toPx())
                    }
                )
                .height(160.dp)
                .fillMaxWidth()
        )
    }
    item { Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars)) }
}

**I noticed a “snap/jump” feel when scrolling, especially when items hit the top/bottom edges. It gets much more noticeable if someone increases Arrangement.spacedBy() (20/50/70dp etc.). My guess is the combination of:

large inter-item spacing (spacedBy)

heavy per-item effects (drawBackdrop + vibrancy + lens)

lazy composition adding/removing items near edges

What fixed it for me (same look, smoother)

Instead of big verticalArrangement = spacedBy(...), keep the list arrangement simple and put the spacing inside each item via Modifier.padding(vertical = …). This avoids the “edge snap” feeling while keeping the same visual gap.

Also, for performance, cache the dp.toPx() conversion once (don’t compute it inside every draw).

Example pattern:**

val listState = rememberLazyListState()

LazyColumn(
    state = listState,
    modifier = Modifier.fillMaxSize(),
    contentPadding = PaddingValues(
        top = WindowInsets.systemBars.asPaddingValues().calculateTopPadding(),
        bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
    )
) {
    items(items, key = { it.id }) { item ->
        Box(
            Modifier
                .fillMaxWidth()
                .padding(vertical = 8.dp) // spacing here, not spacedBy()
                .drawBackdrop(
                    backdrop = backdrop,
                    shape = { ContinuousRoundedRectangle(32.dp) },
                    effects = {
                        vibrancy()
                        lens(lensInnerPx, lensOuterPx) // cached px values
                    }
                )
                .height(160.dp)
        )
    }
}

(Optional) I also added a draggable scrollbar (LazyColumnScrollbar) for long lists, but the main smoothness improvement came from moving spacing into the item and avoiding layout changes at the edges.

lemme share part of my code so you can lern you are 10000 love you but lets do it smooth thanks me later

 LazyColumnScrollbar(
            state = listState,
            settings = my.nanihadesuka.compose.ScrollbarSettings.Default.copy(
                alwaysShowScrollbar = false,
                thumbThickness = 6.dp,
                scrollbarPadding = 6.dp
            )
        ) {
            LazyColumn(
                state = listState,
                modifier = Modifier
                    .fillMaxSize()
                    .padding(horizontal = 8.dp)
                    .layerBackdrop(listBackdrop), // backdrop for tabs or sheets 
                contentPadding = PaddingValues(
                    top = WindowInsets.systemBars.asPaddingValues().calculateTopPadding(),
                    bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 10.dp
                )
            ) {
                items(
                    items = entries,
                    key = { it.id },
                    contentType = { "feedbackRow" }
                ) { entry ->
                    val isSelected = selectedIds.contains(entry.id)

                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(vertical = 15.dp) // this replaces spacedBy(70.dp) or any
                            .animateItem(
                                fadeInSpec = tween(160),
                                fadeOutSpec = tween(110),
                                placementSpec = null
                            )
                    ) {
                        FeedbackGlassRow(
                            backdrop = backdrop, // ✅ keep
                            entry = entry,
                            isSelected = isSelected,
                            selectionMode = selectionMode,
                            onToggleSelection = { onToggleSelection(entry) },
                            onOpenDetails = { onOpenDetails(entry) }
                        )
                    }
                }

                item {
                    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
                    Spacer(Modifier.height(10.dp))
                }
            }
        }
    }
}
Screen_Recording_20251218_164239_Feedback.mp4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions