Android 12 Developer Preview is here! Try it out, and give us your feedback!

Transition

class Transition<S>
kotlin.Any
   ↳ androidx.compose.animation.core.Transition

Transition manages all the child animations on a state level. Child animations can be created in a declarative way using Transition.animateFloat, Transition.animateValue, animateColor etc. When the targetState changes, Transition will automatically start or adjust course for all its child animations to animate to the new target values defined for each animation.

After arriving at targetState, Transition will be triggered to run if any child animation changes its target value (due to their dynamic target calculation logic, such as theme-dependent values).

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.input.pointer.pointerInput

// enum class ComponentState { Pressed, Released }
var useRed by remember { mutableStateOf(false) }
var toState by remember { mutableStateOf(ComponentState.Released) }
val modifier = Modifier.pointerInput(Unit) {
    detectTapGestures(
        onPress = {
            toState = ComponentState.Pressed
            tryAwaitRelease()
            toState = ComponentState.Released
        }
    )
}

// Defines a transition of `ComponentState`, and updates the transition when the provided
// [targetState] changes. The tran
// sition will run all of the child animations towards the new
// [targetState] in response to the [targetState] change.
val transition: Transition<ComponentState> = updateTransition(targetState = toState)
// Defines a float animation as a child animation the transition. The current animation value
// can be read from the returned State<Float>.
val scale: Float by transition.animateFloat(
    // Defines a transition spec that uses the same low-stiffness spring for *all*
    // transitions of this float, no matter what the target is.
    transitionSpec = { spring(stiffness = 50f) }
) { state ->
    // This code block declares a mapping from state to value.
    if (state == ComponentState.Pressed) 3f else 1f
}

// Defines a color animation as a child animation of the transition.
val color: Color by transition.animateColor(
    transitionSpec = {
        when {
            ComponentState.Pressed isTransitioningTo ComponentState.Released ->
                // Uses spring for the transition going from pressed to released
                spring(stiffness = 50f)
            else ->
                // Uses tween for all the other transitions. (In this case there is
                // only one other transition. i.e. released -> pressed.)
                tween(durationMillis = 500)
        }
    }
) { state ->
    when (state) {
        // Similar to the float animation, we need to declare the target values
        // for each state. In this code block we can access theme colors.
        ComponentState.Pressed -> MaterialTheme.colors.primary
        // We can also have the target value depend on other mutableStates,
        // such as `useRed` here. Whenever the target value changes, transition
        // will automatically animate to the new value even if it has already
        // arrived at its target state.
        ComponentState.Released -> if (useRed) Color.Red else MaterialTheme.colors.secondary
    }
}
Column {
    Button(
        modifier = Modifier.padding(10.dp).align(Alignment.CenterHorizontally),
        onClick = { useRed = !useRed }
    ) {
        Text("Change Color")
    }
    Box(
        modifier.fillMaxSize().wrapContentSize(Alignment.Center)
            .size((100 * scale).dp).background(color)
    )
}

Summary

Nested classes

Segment holds initialState and targetState, which are the beginning and end of a transition.

Extension functions
From androidx.compose.animation
State<Color>
Transition<S>.animateColor(noinline transitionSpec: Transition.Segment<S>.() -> FiniteAnimationSpec<Color> = { spring() }, label: String = "ColorAnimation", targetValueByState: (state: S) -> Color)

Creates a Color animation as a part of the given Transition.

From androidx.compose.animation.core
State<Dp>
Transition<S>.animateDp(noinline transitionSpec: Transition.Segment<S>.() -> FiniteAnimationSpec<Dp> = { spring(visibilityThreshold = Dp.VisibilityThreshold) }, label: String = "DpAnimation", targetValueByState: (state: S) -> Dp)

Creates a Dp animation as a part of the given Transition.

State<Float>
Transition<S>.animateFloat(noinline transitionSpec: Transition.Segment<S>.() -> FiniteAnimationSpec<Float> = { spring() }, label: String = "FloatAnimation", targetValueByState: (state: S) -> Float)

Creates a Float animation as a part of the given Transition.

State<Int>
Transition<S>.animateInt(noinline transitionSpec: Transition.Segment<S>.() -> FiniteAnimationSpec<Int> = { spring(visibilityThreshold = 1) }, label: String = "IntAnimation", targetValueByState: (state: S) -> Int)

Creates a Int animation as a part of the given Transition.

State<IntOffset>