Skip to content

Spring animations with MotionScheme in Compose

Short answer: read MaterialTheme.motionScheme and pass one of its six specs as the animationSpec:

  • defaultSpatialSpec(), fastSpatialSpec() or slowSpatialSpec() for size, position, corners and morphs
  • …EffectsSpec() for color and alpha

With MotionScheme.expressive() the spatial specs bounce slightly. The effects specs never do.

Expressive · fast spatialdamping 0.6 · stiffness 800
Expressive · default spatialdamping 0.8 · stiffness 380
Standard · default spatialdamping 0.9 · stiffness 700
Effects · default (color, alpha)damping 1 · stiffness 1600
@Composable
fun SelectableTile(selected: Boolean, modifier: Modifier = Modifier) {
val motion = MaterialTheme.motionScheme
// Size and corner changes are spatial: they may overshoot (bounce) with MotionScheme.expressive().
val size by animateDpAsState(
targetValue = if (selected) 120.dp else 96.dp,
animationSpec = motion.defaultSpatialSpec(),
label = "size",
)
val corner by animateDpAsState(
targetValue = if (selected) 48.dp else 16.dp,
animationSpec = motion.fastSpatialSpec(),
label = "corner",
)
// Color and alpha are effects: they never overshoot, in either scheme.
val color by animateColorAsState(
targetValue = if (selected) MaterialTheme.colorScheme.primaryContainer
else MaterialTheme.colorScheme.surfaceContainerHigh,
animationSpec = motion.defaultEffectsSpec(),
label = "color",
)
Box(modifier.size(size).background(color, RoundedCornerShape(corner)))
}

A tween has a fixed duration and curve. When someone taps again mid-animation it either restarts or jumps. A spring keeps its velocity and retargets smoothly. Material components already use the theme’s springs, so a custom tween(300) next to them looks out of place.

Spring values and scheme choice →

Want your agent to get this right every time? Install the skill. If this page helped,star the repo on GitHub.

Built by Sanikant. Set in Google Sans Flex (SIL Open Font License), icons from Material Symbols (Apache 2.0). Material Design is a Google trademark; this project is not affiliated with Google.