← Back to list

Animating Item Placement in Lazy Lists

When a list reorders, adds a row, or removes one, the default behavior is abrupt. Items just snap to their new positions with no…

Christophy Barth · 2026-07-09 11:31 · 0 claps · 2.0 min read
#android-animations #jetpack-compose #kotlin #android-development #mobile-app-development
Open on Medium ↗
Wiki topics: 📱 · Mobile Development 🎬 · Film & Television

Animating Item Placement in Lazy Lists

When a list reorders, adds a row, or removes one, the default behavior is abrupt. Items just snap to their new positions with no transition, and a sort or a delete that should feel smooth instead jumps. Compose can animate all of it for you, and these days it’s a single modifier. If you learned this a while ago, the API also changed, so it’s worth a refresher even if you’ve done it before.

What changed

The old way was Modifier.animateItemPlacement(), and it only handled items moving around. It's deprecated now. The replacement is Modifier.animateItem(), which is no longer experimental and covers three things at once: items fading in when they appear, fading out when they leave, and sliding when they change position. If you've still got animateItemPlacement in your code, swapping it for animateItem is the basic migration.

The one requirement people miss

None of this works without stable keys on your items. Compose can only animate a row from one position to another if it can recognize that it’s the same row before and after the change, and the key is how it knows. Without keys, items are tracked by index, and a reorder just looks like every position got new content, so there's nothing to animate.

LazyColumn {
    items(tasks, key = { it.id }) { task ->
        TaskRow(
            task = task,
            modifier = Modifier.animateItem()
        )
    }
}

That’s the whole setup. Stable key on the item, animateItem() on the row's top-level modifier, and now reordering your tasks list animates each row to its new spot while additions fade in and removals fade out.

Tuning the motion

Calling animateItem() bare gives you sensible defaults, but the three transitions are independently configurable through its parameters. You can hand it a placementSpec for the movement and fadeInSpec and fadeOutSpec for appearance and disappearance respectively, which is useful when the default fade feels too slow, or you want the reordering to settle with a bit of spring:

Modifier.animateItem(
    fadeInSpec = tween(durationMillis = 250),
    placementSpec = spring(
        stiffness = Spring.StiffnessMediumLow,
        visibilityThreshold = IntOffset.VisibilityThreshold
    ),
    fadeOutSpec = tween(durationMillis = 100)
)

A quick fade out paired with a slightly springy placement is the combination I keep coming back to, because removals get out of the way fast while the rows that shift settle with a little weight.

Keep an eye on the work behind it

One practical caution. Animated reordering looks best on lists where changes are occasional, like a user sorting or checking off a task. If your list is churning many items many times a second, all those simultaneous animations are real work, and the effect can turn busy rather than smooth. So, use it where motion communicates something to the user, and it earns its place. Where the list is just rapidly refreshing data, the animation is complete noise.

May your reorders glide and your deletions leave without a fuss.


메타데이터
post_id
fdeafadab9c2
slug
animating-item-placement-in-lazy-lists-fdeafadab9c2
url
https://medium.com/@christophybarth/animating-item-placement-in-lazy-lists-fdeafadab9c2
canonical_url
https://medium.com/@christophybarth/animating-item-placement-in-lazy-lists-fdeafadab9c2
author_url
https://medium.com/@christophybarth
status
ok
fetched_at
2026-09-17 10:54:01