Reputation: 83
I want to animate the task item placement to the bottom of the list when the task item checked (isDone == true
).
This is the code for the Lazy Column:
LazyColumn(
modifier = Modifier.padding(paddingValues),
state = listState,
contentPadding = PaddingValues(16.dp)
) {
items(tasks) { task ->
TaskItem(
task = task,
onEvent = viewModel::onEvent,
onItemClick = {
viewModel.onEvent(TaskEvents.OpenOrCreateTask(task.id))
containerState = ContainerState.Fullscreen
},
modifier = Modifier
.fillMaxWidth()
.border(BorderStroke(2.dp, Color.Black))
.padding(8.dp)
)
}
}
This is the data class for the task item (isDone
represents if the task is completed or not).
I want the completed tasks to appear at the end of the list but also want to animate it.
@Entity
data class Task(
val title: String,
val description: String?,
val isDone: Boolean,
@PrimaryKey val id: Int? = null,
)
I tried the animateContentPlacement
modifier and can't figure anything else.
Upvotes: 1
Views: 138
Reputation: 15579
Using the animateItemPlacement
modifier on your TaskItem is the correct way to go (for Compose versions < 1.7, see below), but as the documentation explains, you must explicitly provide a key to items
:
When you provide a key via
LazyListScope.item
/LazyListScope.items
this modifier will enable item reordering animations.
When your Task's id
is unique and you can guarantee that null
does not occur more than once in the list at any given time, you can do it like this:
items(
items = tasks.sortedBy(Task::isDone),
key = { it.id ?: 0 },
) { task ->
// ...
}
Note that tasks.sortedBy(Task::isDone)
is used to order the tasks that are done at the bottom of the list.
Keep in mind that animateItemPlacement
does not animate new and removed elements, only reordered elements. To improve that behavior the next Compose version (1.7) will deprecate this function and introduce animateItem
as a replacement. You can try this out already with the current (at the time of writing) beta version 1.7.0-beta05
.
Upvotes: 0
Reputation: 100
You have to use key for the items, and .animateItem() modifier to your child items. Similar to what @Leviathan said,
Key should not be null neither same. // You can combine multiple properties to make a unique key combination
Add .animateItem() to your child item.
For your case,
LazyColumn(
modifier = Modifier.padding(paddingValues),
state = listState,
contentPadding = PaddingValues(16.dp)
) {
items(
items = tasks.sortedBy { it.isDone }, // or sortedByDescending { it.isDone }
key = { "${ it.id ?: 0 } - ${ it.isDone } - ${ it.title }" }, // You can combine multiple properties to make a unique key combination
) { task ->
TaskItem(
task = task,
onEvent = viewModel::onEvent,
onItemClick = {
viewModel.onEvent(TaskEvents.OpenOrCreateTask(task.id))
containerState = ContainerState.Fullscreen
},
modifier = Modifier
.fillMaxWidth()
.animateItem() // add this to your child's modifier
.border(BorderStroke(2.dp, Color.Black))
.padding(8.dp)
)
}
}
You are good to go!
Upvotes: 0