[Transition] manages all the child animations on a state level.
GestureAnimationSample
@Composable
fun GestureAnimationSample() {
// 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 transition 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)
)
}
}