A Quick Guide to the animate*AsState Animation API in Jetpack Compose

Pranav Jayaraj
6 min readMar 16, 2021
Gif credits to Sherchle

Creating complex animations have never been easy in Android. Thanks to Jetpack Compose, we now have multiple animation APIs to make our task much easier when creating animations. These APIs are composable functions built on the low-level animation APIs and guess what ? they are built using Kotlin coroutines. The Jetpack compose is currently in beta and even though there are experimental APIs, They give us a glimpse of what the future of Android is going to look like and it is really exciting.

Before reading this article it is good to have some familiarity with concepts like the compose layout and compose state APIs. Because UI updation in compose aka “Recomposition” is based on state changes on the data element. But don’t worry we will be writing another article specifically on these aspects soon.

The “animate*AsState” API:

Jetpack provides a very simple API called the animate*AsState where the * denotes that you can replace a data type there in its place and animate it. The value maybe a colour, an integer, a float, a density independent pixel etc. If you want to animate the colour values we would use “animateColorAsState” API.

fun animate*AsState(targetValue: *,
animationSpec: AnimationSpec<*> = defaultAnimation,
finishedListener: ((*) -> Unit)? = null)

the function “animate*AsState()” accepts a target value and will keep on animating until it has reached a given target value. The target value may be a colour, float, int, density independent pixel or a custom data type etc. An animation specification is passed to the function to define the animating properties which would decide how the value is going to get animated. By default it uses an animation specification called as Spring. And we also have a finished listener which can be used to get a notification when the animation is finished. There are also extra properties attached to the api depending on the kind of data type we are animating.

Now let us take a look at an example.

val startColor = Color.Blue val endColor = Color.Greenval backgroundColor by animateColorAsState(
if (state) endColor else startColor)

In the above example we are using the “animateColorAsState” API. Here the animate*AsState API animates the colour data type. If we are using “animateFloatAsState” API then the animating value would be a float and so on. From the above example we can see how the colour animates from blue to green and vice versa when we click the animate button. This is because we are changing the value of the state variable and since there is a state change our animation is executed. You can take a look at the source code from below.

Final code

Now in the above example we have not used any animationSpec or notification listener but we simply passed a target value. Since we did not specify an animation spec it used the default animation spec i.e Spring.

Another interesting thing to note is that the animation spec property is not only present in the animate*AsState api but also in every other APIs in which we need to specify a target value. There are multiple inbuilt animation specs which are ready to use predefined in compose. We will be taking a quick look at each one of them along with some code.

Animaton Spec

The Animation Spec in compose comes inbuilt with some of the commonly used animation patterns in everyday life which we can customise with our values to get the required results.

Spring

This is the default animation spec present in the animations apis. It is used to provide spring like animation when moving towards a specified target value.

val backgroundColor by animateColorAsState(
if (state) endColor else startColor,
animationSpec = spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessMedium
)
)

Since we are using colour data type. Colour transitions from blue to green and vice versa just like a spring. The damping ratio and stiffness is used to set the properties of the spring in order to specify its behaviour.

Tween

For animating toward a target value over a specified time. It also accepts an easing curve where we can specify the kind of easing to happen. Easing denotes how the value will move from the initial value towards the target value. For example the value may start slow and end up towards the target value very fast or it may start fast and end up slowly towards the target value and so on. There are multiple types of inbuilt easing values provided which you can take a look at for more details.

val backgroundColor by animateColorAsState(
if (state) endColor else startColor,
animationSpec = tween(
durationMillis = 2000,
delayMillis = 40,
easing = LinearOutSlowInEasing
)
)

Repeatable

Repeatable just like its name it is used to create a one time repeating animations between the initial and target value. We can also specify the no of times the repetitions that must occur, repetition direction and animation that should repeat.

val backgroundColor by animateColorAsState(
if (state) endColor else startColor,
animationSpec = repeatable(
iterations = 3,
animation = tween(durationMillis = 200),
repeatMode = RepeatMode.Reverse
)
)

Infinite Repeatable

Similar to repeatable but it is used to create infinitely repeating animations between the initial and target value.

val backgroundColor by animateColorAsState(
if (state) endColor else startColor,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 200),
repeatMode = RepeatMode.Reverse
)
)

Snap

Snap is used to animate from one value to another quickly also we can setup a delay in between the transitions.

Snap is used to toggle between two different values immediately

val backgroundColor by animateColorAsState(
if (state) endColor else startColor,
animationSpec = snap(delayMillis = 20)
)

Keyframes

Keyframes gives us more control over the animation specification. It lets us control at what time a particular animation must happen and we can also set the corresponding easing that must happen during that phase of the animation.

What is happening under the hood ?

During animation, the animating value is represented as an AnimationVector. For example let us take the colour data type as example. Colour contains 4 values RGB and alpha, hence colour is converted into an AnimationVector4D that holds 4 float values namely Red, Blue, Green and Alpha. Every data type used in animations is converted to either AnimationVector1D, AnimationVector2D, AnimationVector3D, or AnimationVector4D depending on its dimensions. We can create our own TwoWayConverter to support our own custom data types for animations.

Below you can find the entire source code of everything mentioned in this article.

Final code

--

--

Pranav Jayaraj

Android Engineer with 4+ years working for early stage product startups