DEV Community

myougaTheAxo
myougaTheAxo

Posted on

LazyColumn Tips — Sticky Headers, Scroll Control & Infinite Scroll

Optimize LazyColumn performance and add advanced scrolling features.

Sticky Headers for Grouped Lists

Add persistent section headers:

val grouped = items.groupBy { it.category }

LazyColumn {
    grouped.forEach { (category, items) ->
        stickyHeader {
            Text(
                category,
                modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Gray)
                    .padding(16.dp),
                fontWeight = FontWeight.Bold
            )
        }
        items(items) { item ->
            ItemRow(item)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Scroll Position Control

Remember and restore scroll position:

val listState = rememberLazyListState()

LazyColumn(state = listState) {
    items(items) { item ->
        ItemRow(item)
    }
}

// Scroll to specific index
Button(onClick = {
    scope.launch {
        listState.animateScrollToItem(0)
    }
})
Enter fullscreen mode Exit fullscreen mode

Scroll-to-Top FAB

Show floating action button for quick scrolling:

val listState = rememberLazyListState()
val isVisible = listState.firstVisibleItemIndex > 3

FloatingActionButton(
    onClick = { scope.launch { listState.animateScrollToItem(0) } },
    modifier = Modifier.alpha(if (isVisible) 1f else 0f)
) {
    Icon(Icons.Default.ArrowUpward, contentDescription = "Scroll to top")
}

LazyColumn(state = listState) { ... }
Enter fullscreen mode Exit fullscreen mode

Animate Item Changes

Add smooth animations for item additions/removals:

LazyColumn {
    items(items, key = { it.id }) { item ->
        ItemRow(
            item,
            modifier = Modifier.animateItem()
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Infinite Scroll with derivedStateOf

Load more items as user scrolls to bottom:

val listState = rememberLazyListState()
val isNearBottom = remember {
    derivedStateOf {
        val totalItems = items.size
        val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
        lastVisibleItem >= totalItems - 3
    }
}

LaunchedEffect(isNearBottom.value) {
    if (isNearBottom.value) {
        viewModel.loadMore()
    }
}

LazyColumn(state = listState) {
    items(items) { item ->
        ItemRow(item)
    }
}
Enter fullscreen mode Exit fullscreen mode

Master these techniques to build smooth, performant scrolling experiences.


8 production-ready Android app templates on Gumroad.

Browse templatesGumroad

Top comments (0)