I am using a LazyColumn
in a checklist like style. The list shows all to-be-done items first and all done items last. Tapping on an item toggles whether it is done.
Here is an MWE of what I am doing:
data class TodoItem(val id: Int, val label: String, var isDone: Boolean)
@Composable
fun TodoCard(item: TodoItem, modifier: Modifier, onClick: () -> Unit) {
val imagePainterDone = rememberVectorPainter(Icons.Outlined.Done)
val imagePainterNotDone = rememberVectorPainter(Icons.Outlined.Add)
Card(
modifier
.padding(8.dp)
.fillMaxWidth()
.clickable {
onClick()
}) {
Row {
Image(
if (item.isDone) imagePainterDone else imagePainterNotDone,
null,
modifier = Modifier.size(80.dp)
)
Text(text = item.label)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ExampleColumn() {
val todoItems = remember {
val list = mutableStateListOf<TodoItem>()
for (i in 0..20) {
list.add(TodoItem(i, "Todo $i", isDone = false))
}
list
}
val sortedTodoItems by remember {
derivedStateOf { todoItems.sortedWith(compareBy({ it.isDone }, { it.id })) }
}
LazyColumn {
items(sortedTodoItems, key = {it.label}) { item ->
TodoCard(item = item, modifier = Modifier.animateItemPlacement()) {
val index = todoItems.indexOfFirst { it.label == item.label }
if (index < 0) return@TodoCard
todoItems[index] = todoItems[index].copy(isDone = !todoItems[index].isDone)
}
}
}
}
This work well except for one side effect introduced with Modifier.animateItemPlacement()
: When toggling the first currently visible list element, the LazyListState
will scroll to follow the element.
Which is not what I want (I would prefer it to stay at the same index instead).
I found this workaround, suggesting to scroll back to the first element if it changes, but this only solves the problem if the first item of the column is the first one to be currently displayed. If one scrolls down such that the third element is the topmost visible and taps that element, the column will still scroll to follow it.
Is there any way to decouple automatic scrolling from item placement animations? Both seem to rely on the LazyColumn
's key
parameter?