'Scroll to top when adding new items

I have a usecase where I would like a LazyColumn to scroll to the top if a new item is added to the start of the list - but only if the list was scrolled to top before. I'm currently using keys for bookkeeping the scroll position automatically, which is great for all other cases than when the scroll state is at the top of the list.

This is similar to the actual logic I have in the app (in my case there is however no button, showFirstItem is a parameter to the composable function, controlled by some other logic):

var showFirstItem by remember { mutableStateOf(true) }
Column {
    Button(onClick = { showFirstItem = !showFirstItem }) {
        Text("${if (showFirstItem) "Hide" else "Show"} first item")
    }

    LazyColumn {
        if (showFirstItem) {
            item(key = "first") {
                Text("First item")
            }
        }

        items(count = 100,
            key = { index ->
                "item-$index"
            }
        ) { index ->
            Text("Item $index")
        }
    }
}

As an example, I would expect "First item" to be visible if I scroll to top, hide the item and them show it again. Or hide the item, scroll to top and then show it again.

I think the solution could be something with LaunchedEffect, but I'm not sure at all.



Solution 1:[1]

You can scroll to the top of the list on a LazyColumn like this:

val coroutineScope = rememberCoroutineScope()
...
Button(onClick = {
    coroutineScope.launch {
        // 0 is the first item index
        scrollState.animateScrollToItem(0)
    }
}) {
    Text("Scroll to the top")
}

So call scrollState.animateScrollToItem(0) where ever you need from a coroutine, e.g. after adding a new item.

Solution 2:[2]

In your item adding logic,

scrollState.animateScrollToItem(0)
//Add an optional delay here
showFirst = ... //Handle here whatever you want

Here, scrollState is to be passed in the LazyColumn

val scrollState = rememberScrollState() LazyColumn(state = scrollState) { ... }

Solution 3:[3]

If a new item has been added and user is at top, the new item would not appear unless the list is scrolled to the top. I have tried this:

if (lazyListState.firstVisibleItemIndex <= 1) {
            //scroll to top to ensure latest added book gets visible
            LaunchedEffect(key1 = key) {
                lazyListState.scrollToItem(0)
            }
        }
LazyColumn(
            modifier = Modifier.fillMaxSize(),
            state = lazyListState
        ) {...

And it seems to work. But it breaks the pull to refresh component that I am using. So not sure how to solve that. I am still trying to force myself to like Compose. Hopefully that day will come =)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hasan
Solution 2 Richard Onslow Roper
Solution 3 Kasper Finne Nielsen