What's the best way to animate insertion and deletion animations in lazy column or row with multiple item types similar to how it's done using DiffUtil?
Asked
Active
Viewed 5,712 times
4
-
Not a duplicate. – Kevin Krumwiede Aug 15 '23 at 18:44
-
@KevinKrumwiede please vote to reopen – Charles Woodson Aug 15 '23 at 20:50
1 Answers
7
https://issuetracker.google.com/issues/150812265
Modifier.animateItemPlacement() was created for this reason, but to do it with multiple item types is less straight forward.
Animation demo: https://youtube.com/shorts/FBwMV1HoAoQ?feature=share
Ps (for demo)
- RewardItem click used to remove reward items and CartHeader click adds them back
- CartItem remove button click to remove item from cart item and modify button click to add it back
Sealed Class:
sealed class CartListItems(open val id: String = "") {
class RewardHeaderItem(override val id: String, val title: String) : CartListItems()
class RewardListItem(override val id: String, val rewards: List<RewardItem>) : CartListItems()
class CartHeaderItem(override val id: String, val title: String) : CartListItems()
class CartListItem(override val id: String, val cartItem: CartItem) : CartListItems()
}
Inside ViewModel:
val cartListItems: StateFlow<List<CartListItems>> =
combine(
rewardItems,
cartItems
) { rewardItems, cartItems ->
buildCartList(rewardItems, cartItems)
}.stateIn(
scope = viewModelScope,
started = Eagerly,
initialValue = emptyList()
)
private fun buildCartList(rewardItems: List<RewardItem>, cartItems: List<CartItem>): List<CartListItems> {
val items = ArrayList<CartListItems>()
if (rewardItems.isNotEmpty()) {
items.add(
CartListItems.RewardHeaderItem("rewards-header", "Your Rewards")
)
items.add(
CartListItems.RewardListItem("rewards-list", rewardItems)
)
}
if (cartItems.isNotEmpty()) {
items.add(
CartListItems.CartHeaderItem("cart-header", "Your Cart")
)
items.addAll(
cartItems.map { CartListItems.CartListItem("cart-item:${it.id}", it) }
)
}
return items
}
List Composable:
@Composable
private fun CartList(
cartViewModel: CartViewModel = viewModel()
) {
val listItems by cartViewModel.cartListItems.collectAsState()
LazyColumn(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
items(listItems, key = { it.id }) { listItem ->
when (listItem) {
is CartListItems.RewardHeaderItem -> {
Box(modifier = Modifier.animateItemPlacement()) {
RewardsHeader()
}
}
is CartListItems.RewardListItem -> {
Box(modifier = Modifier.animateItemPlacement()) {
RewardsList(listItem.rewards)
}
}
is CartListItems.CartHeaderItem -> {
Box(modifier = Modifier.animateItemPlacement()) {
CartHeader()
}
}
is CartListItems.CartListItem -> {
Box(modifier = Modifier.animateItemPlacement()) {
CartItem(listItem.cartItem)
}
}
}
}
}
}

Charles Woodson
- 682
- 1
- 8
- 22
-
1So it looks like the list items are moving correctly, but this still isn't doing enter/exit animations for items. – frodo2975 Jun 15 '22 at 15:46