Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compose LazyColumn key, messes up scrolling when sorting the items

I'm trying to implement simple sort with items that are in a state.

This will work perfectly, only problem is that the animation is now gone, because it doesn't have a key.

LazyColumn(
    state = listState,
) {
    items(items.size) { index ->
        val ticker = items[index]
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .animateItemPlacement(), // This won't work
        ) {
            Item(...)
        }
    }
}

But If I try to change it to:

items(items.size, key = { items[it].name }) { index ->

or If I use:

items(items, key = { items[it].name }) { item ->

It will have animations, but it will move items above and below current scroll position (even if you don't move). The wanted result is that you stay on top of the items, because we didn't move.

This is in a viewModel:

private val _state = MutableStateFlow<Response<List<Item>>>(Response.Loading)
val state get() = _state
private fun updateList() {
    viewModelScope.launch(Dispatchers.IO) {
        client.getItems()
            .onSuccess {
                unFilteredList = it.toMutableList()

                val filteredList = filterList()
                _tickerListState.value = Response.Success(filteredList)
            }
            .onFailure {}
    }
}
like image 933
WinterChilly Avatar asked Sep 05 '25 01:09

WinterChilly


2 Answers

I've added an empty item at the top to workaround this behavior as suggested by this comment in the Google issue tracker.

Also I'm scrolling to the top with a LaunchedEffect when the sorting criteria change.

LazyColumn(state = rememberLazyListState()) {
    item(key = "0") {
        Spacer(Modifier.height(12.dp)) // I need to add some padding so I use the empty item for this 
    }
    items(items) {
        ...
    }
}
like image 51
Nieto Avatar answered Sep 07 '25 17:09

Nieto


Semi-Fixed the problem with:

LaunchedEffect(items.first()) {
    listState.animateScrollToItem(0)
}
LazyColumn{
        items(items, key = { it.id}) { item-> ...
}

Sometimes the animation skips, but it works 90% of the time. If I remove the animateScrollToItem, the animation looks better, but then there is a scroll position issue.

Edit: Because I had search I had to improve the logic:

LaunchedEffect(items.firstOrNull()) {
    if (items.isNotEmpty() && searchQuery.isEmpty()) {
        listState.animateScrollToItem(0)
    }
}

This now works like it should in the beginning.

like image 37
WinterChilly Avatar answered Sep 07 '25 16:09

WinterChilly