Enable Auto-scrolling LazyColumn to the bottom when reverseLayout = false
Asked Answered
H

5

11

I have a LazyColumn holding some Items. I listen a Flow from Room and everything works great when reverseLayout = true. When new Item get inserted into the database, the LazyColumn scrolls to the bottom and shows last Item just fine. But reverseLayout = true inverts the headers too. So I disabled it with reverseLayout = false. This does not work in that when Item get inserted, it is shown on the list but the list does not get scrolled to show the bottom item. I have to manually scroll.

How can I scroll to the bottom Item when the LazyColumn get recomposed on items change?

I don't think I need to put the code since the problem happens with any use of LazyColumn but if that is important let me know and I can redact the code and post them!

Homeless answered 4/5, 2022 at 10:15 Comment(3)
this is a known bug, star it to bring more attentionNoheminoil
Thanks for bringing attention to that one. I have starred it. Hope it get fixedHomeless
@Stefano Mtangoo did you find an answer for your question ? because I'm looking for the answer to the same question and I couldn't find a suitable answer for my own code.Donothingism
F
11

In a messaging app i scroll to bottom using size of items and LazyListState

as

coroutineScope.launch {
    scrollState.animateScrollToItem(messages.size - 1)
}

and whenever user inputs a message it gets added to

 val messages = remember { mutableStateListOf<ChatMessage>() }

you can call scroll in a LaunchedEffect(messages.size){...} for it to be invoked only when recomposition happens and item count has changed

Frontal answered 4/5, 2022 at 10:28 Comment(3)
for some reason, this does not work. The first one produces an error LaunchEffect is calling animateScrollToItem but it does not actually scroll!Homeless
I used this solution it works but produces a flickering effect on the screen as it scrolls down, is there a way I can work around it such that the flickering is not seen as it scrolls or a way to make it scroll more smoothly maybe?Ponce
You might have all your items recomposing while you scroll. To prevent this you can us SnapshotStateList via mutableStateListOf and if you do use keys with unique ids and check if all of items are recomposing. That might be causing the flickering if all of the items are being added againFrontal
W
5

You can achieve that behavior by this:

   val uiState = chatViewModel.uiState.collectAsState()
   val chatListState = rememberLazyListState()

   LaunchedEffect(uiState.value.messages){
    chatListState.animateScrollToItem(chatListState.layoutInfo.totalItemsCount)
   }

        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            contentPadding = PaddingValues(16.dp),
            verticalArrangement = Arrangement.spacedBy(24.dp),
            state = chatListState,
        ) {
            items(uiState.value.messages) {
Wish answered 4/10, 2023 at 17:31 Comment(0)
M
2

It is a very late answer, but I wrote on the LazyColumn a corroutineScope with the lazyColumnState call to scroll, my problem was on the first 10 items and I needed to stay on the first item. Maybe with this you can figure it out.

val lazyColumnListState = rememberLazyListState()
val corroutineScope = rememberCoroutineScope()

LazyColumn(
          modifier = Modifier.fillMaxWidth(),
          contentPadding = PaddingValues(vertical = 4.dp),
          state = lazyColumnListState
         ) {

            corroutineScope.launch {
                  if(itemCount == 10){
                     lazyColumnListState.scrollToItem(0)
                  }
            }

           items(
                items = ...
Mannish answered 23/5, 2023 at 14:54 Comment(0)
G
1
LaunchedEffect(messages) {
    if (messages.isNotEmpty()) {
        listState.scrollToItem(messages.size - 1)
    }
}

in my case i used this , and this is working( i used this after when user send the message)

Groveman answered 1/7 at 6:45 Comment(2)
it will be great to explain variables like listState and where they come from, to make your example helpfulHomeless
Sure, keep in my mind (next time)Groveman
C
0

@Thracian solution works, but it produces flickering effect on system scroll to last item, despite using SnapshotStateList for state list & providing unique keys for items.

However quite weirdly i overcome this problem by adding the new item to the beginning of the list and scrolling to that item respectively. (it worth to note that in any case i tried, the items visible to user gets recomposed on scrolling)

So, you could:

#1 add new item to the start of the state list:

// stateList: SnapshotStateList<Data>
stateList.add(0, data)

#2 for lazy column implementation use:

val scrollState = rememberLazyListState()
LaunchedEffect(stateList.size) {
    if (stateList.isNotEmpty()) scrollState.animateScrollToItem(0)
}

LazyColumn(
    modifier = modifier,
    state = scrollState,
    reverseLayout = true
) {
    // your logic for data item composition
}

The result:

Chat screen quick demo GIF

Countryandwestern answered 30/7 at 8:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.