Mobile Development 12 min read

Deep Dive into animateValueAsState and Custom animateXxxAsState APIs in Jetpack Compose

This article explains how Jetpack Compose’s animateValueAsState underpins the animateXxxAsState family, explores its source code, demonstrates how to create custom animation APIs such as animateDpSizeAsState and animateUploadAsState, and provides practical Kotlin examples for building reusable UI animations on Android.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Deep Dive into animateValueAsState and Custom animateXxxAsState APIs in Jetpack Compose

The article begins by noting that the previously introduced animateXxxAsState APIs all delegate to animateValueAsState , and it proceeds to examine the implementation of animateDpAsState as a concrete example.

Source code for animateDpAsState shows a simple composable that returns the result of animateValueAsState with a Dp.VectorConverter . The discussion highlights that most animateXxxAsState functions directly call animateValueAsState , except for a few that add extra handling.

The article then explains the role of TwoWayConverter , an interface that defines conversion between a custom type and an AnimationVector . It shows the definition of the interface and how the companion function TwoWayConverter() creates an implementation ( TwoWayConverterImpl ) to simplify usage.

Next, the sealed class AnimationVector and its concrete subclasses ( AnimationVector1D , AnimationVector2D , AnimationVector3D , AnimationVector4D ) are introduced, with code snippets illustrating their fields and methods.

Using this knowledge, the article demonstrates how to build a custom animateDpSizeAsState API. It defines a DpSize.VectorConverter that maps a DpSize to AnimationVector2D , then creates the composable: @Composable fun animateDpSizeAsState( targetValue: DpSize, finishedListener: ((DpSize) -> Unit)? = null ): State { return animateValueAsState( targetValue, DpSize.VectorConverter, finishedListener = finishedListener ) } A usage example shows a box whose size animates between two DpSize values using the new API, resulting in cleaner code compared to the previous animateSizeAsState approach. The article then tackles a more complex scenario: animating an upload button with five independent properties (text opacity, box width, progress, progress opacity, and background color). Because AnimationVector only supports up to four dimensions, the solution separates the color animation (using animateColorAsState ) and packs the remaining four properties into a data class UploadValue with a TwoWayConverter to AnimationVector4D : data class UploadValue(val textAlpha: Float, val boxWidth: Dp, val progress: Int, val progressAlpha: Float) val UploadValue.Companion.VectorConverter: TwoWayConverter get() = UploadToVector private val UploadToVector = TwoWayConverter( convertToVector = { AnimationVector4D(it.textAlpha, it.boxWidth.value, it.progress.toFloat(), it.progressAlpha) }, convertFromVector = { UploadValue(it.v1, Dp(it.v2), it.v3.toInt(), it.v4) } ) With this converter, a custom composable animateUploadAsState is defined, enabling the entire upload UI (including background color animation) to be driven by a single state object. Finally, the article summarizes that by understanding animateValueAsState , TwoWayConverter , and AnimationVector , developers can create reusable, concise animation APIs for Jetpack Compose, and hints at a future discussion on customizing animationSpec for further control.

animationKotlinMobile UIJetpack ComposeCustom APIanimateValueAsState
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.