Animation in Jetpack Compose
July 1, 2022
This post is meant to be an alternative and a complementary way of presenting information found in https://developer.android.com/jetpack/compose/animation. Laying it out this way helped me make more sense of that documentation and I hope it will help you as well.
First, this post provides a high-level overview of the Animation APIs in Jetpack Compose and then outlined more detail about concrete APIs used in each scenario.
No code snippets here—this post is meant to provide foundational overview of Compose Animation APIs to help you choose most suitable API depending on your animation needs.
Which API to use?
Here is a decision-making diagram to help you chose the right Animation API depending on your needs. More detail about each is provided below.
If animating content change in layout (composition)
If animating appearance and disappearance
If swapping content based on state
If crossfading content
Use
Crossfade
Otherwise, use
AnimatedContent
Otherwise, use
Modifier.animateContentSize
If the animation is state-based and happens during composition
If animation is infinite
If not infinite and animating multiple values simultaneously
Use
updateTransition
Otherwise, use
animate*AsState
If need fine control over animation time
Use
Animation
, such asTargetBasedAnimation
orDecayAnimation
If animation the only source of truth
Use
Animatable
Otherwise, use AnimationState
or animate
Animation APIs in Compose
Brand new APIs written for Jetpack Compose
Many APIs are declarative—you can write animations in a declarative manner.
State-based APIs are interruptible—when an animation is interrupted by another one, the values from the ongoing animation can be carried over to the new one.
Many animations have reasonable defaults (via default function parameters) and are highly customizable with help of
AnimationSpec
andAnimationVector
.Many APIs are built as composable functions on top of lower-level APIs built with coroutine suspend functions.
Android Studio includes powerful tooling support to help you implement and debug animations.
AnimatedVisibility
Composable
Used to animate the appearance and disappearance of its content
Can be customized by
EnterTransition
andExitTransition
Use
Modifier.animateEnterExit
to specify different animation behavior for each direct and indirect child.If only children need to be animated (by using
Modifier.animateEnterExit
), setEnterTransition.None
andExitTransition.None
on the parentAnimatedVisibility
composable.AnimatedVisibility
can be constructed withMutableTransitionState
which allows triggering this animation as soon as theAnimatedVisibility
is added to the composition tree. It is also useful for observing the animation state.
Crossfade
Composable
Animates between two layouts (composables) with a crossfade animation.
Crossfade
expects some kind of state to detect when it should recompose.Use
animationSpec
to customize crossfade animation.
AnimatedContent
Composable
Still experimental as of Compose 1.2.0
Animates its content as it changes based on a target state
Use
transitionSpec
parameter to customize animation behavior
Modifier.animateContentSize
Animates its own size when its child modifier (or the child composable if it is already at the tail of the chain) changes size. This allows the parent modifier to observe a smooth size change.
rememberInfiniteTransition
Composable
Creates a
InfiniteTransition
that runs infinite child animations.Child animations can be added using:
animateColor
animateFloat
animateValue
Child animations will start running as soon as they enter the composition, and will not stop until they are removed from the composition.
Specify an
infiniteRepeatable
to provide the animation specifications.
updateTransition
Composable
Used to apply multiple animations at the same time.
A
Transition
is created by callingupdateTransition(targetState)
Animate between
initialState
andtargetState
using below extension functions on aTransition
:animateColor
animateFloat
animateDp
animateValue
animateInt
animateIntOffset
animateIntSize
animateOffset
animateRect
animateSize
Specify
transitionSpec
parameter to pass a differentAnimationSpec
for each transition state change.Use
isTransitioningTo
infix function intransitionSpec
to determine the direction of the state change.
animate*AsState
Composable
Used for animating a single value. You only need to provide the target value
During the animation,
animate*AsState
composable gets recomposed and returns an updated animation State for every frame.Out of the box, Compose comes with
animate*AsState
for:Float
Color
Dp
Size
Offset
Rect
Int
IntOffset
IntSize
Add support for other data types by providing a
TwoWayConverter
toanimateValueAsState
Customize the animation by providing an
AnimationSpec
Once running, we can’t stop/cancel this animation until it’s removed from the composition tree
Under the hood, lower level API
Animatable
is used byanimate*AsState
Animatable
Not a composable. Can be used outside of a composition
Coroutine-based API
Single Source of Truth (ensures consistent continuation and mutual exclusiveness). The value change is always continuous and any ongoing animation can be canceled and the new animation will start from the current snapshot value with the current velocity.
Animatable
state can be updated usinganimateTo
,snapTo
andanimateDecay
commonly launched in aLaunchedEffect
snapTo
sets the current value to the target value immediately. This is useful when the animation itself is not the only source of truth and has to be synced with other states, such as touch eventsanimateDecay
starts an animation that slows down from the given velocity. This is useful for implementing fling behaviorOut of the box, supports
Float
andColor
, but any data type can be used by providing aTwoWayConverter
.Unlike
animate*AsState
, can have an initial value different from its first target valueCustomizable via
AnimationSpec
Animatable
hasAnimationState
animate and AnimationState
Not a composable. Can be used outside of a composition
Animates from the given
initialValue
towards thetargetValue
with optionalinitialVelocity
. UseanimationSpec
to customize animation behaviorOne shot animation: Unlike
Animatable
, does not provide consistent continuation and mutual exclusivenessanimate
is asuspend
functionExecute multiple animations in the same coroutine to achieve sequential (chained) animations. In the view system, we had to use animation end listeners for this
Execute animations in separate coroutines to achieve simultaneous (parallel) animations
If there's a need to access more info related to the animation such as start time, target, etc, consider using
AnimationState.animateTo