animateColor
@Composable
public inline fun <S> Transition<S>.animateColor(
noinline transitionSpec: @Composable Transition.Segment<S>.() -> FiniteAnimationSpec<Color> = {
spring()
},
label: String = "ColorAnimation",
targetValueByState: @Composable() (state: S) -> Color,
): State<Color>
Creates a Color
animation as a part of the given Transition
. This means the lifecycle of this
animation will be managed by the Transition
.
targetValueByState
is used as a mapping from a target state to the target value of this
animation. Transition
will be using this mapping to determine what value to target this
animation towards. Note that targetValueByState
is a composable function. This means the
mapping function could access states, CompositionLocals, themes, etc. If the target value changes
when the Transition
already reached its targetState
, the Transition
will run an animation to ensure the new target value is reached smoothly.
An optional transitionSpec
can be provided to specify (potentially different) animations for
each pair of initialState and targetState. FiniteAnimationSpec
can be used to describe such
animations, such as tween
, spring
, keyframes
and even repeatable
, but not
infiniteRepeatable
. By default, transitionSpec
uses a spring
animation for all transition
destinations.
label
is used to differentiate from other animations in the same transition in Android Studio.
Returns
A State object, the value of which is updated by animation |
@Composable
public fun InfiniteTransition.animateColor(
initialValue: Color,
targetValue: Color,
animationSpec: InfiniteRepeatableSpec<Color>,
label: String = "ColorAnimation",
): State<Color>
Creates a Color animation that runs infinitely as a part of the given InfiniteTransition
.
Once the animation is created, it will run from initialValue
to targetValue
and repeat.
Depending on the RepeatMode
of the provided animationSpec
, the animation could either restart
after each iteration (i.e. RepeatMode.Restart
), or reverse after each iteration (i.e .
RepeatMode.Reverse
).
If initialValue
or targetValue
is changed at any point during the animation, the animation
will be restarted with the new initial/targetValue. Note: this means animation continuity
will not be preserved when changing either initialValue
or targetValue
.
A label
for differentiating this animation from others in android studio.
Deprecated animateColor APIs now have a new label parameter added.
@Composable
public fun InfiniteTransition.animateColor(
initialValue: Color,
targetValue: Color,
animationSpec: InfiniteRepeatableSpec<Color>,
): State<Color>
Code Examples
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 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)
)
}
}
InfiniteTransitionSample
@Composable
fun InfiniteTransitionSample() {
@Composable
fun InfinitelyPulsingHeart() {
// Creates an [InfiniteTransition] instance for managing child animations.
val infiniteTransition = rememberInfiniteTransition()
// Creates a child animation of float type as a part of the [InfiniteTransition].
val scale by
infiniteTransition.animateFloat(
initialValue = 3f,
targetValue = 6f,
animationSpec =
infiniteRepeatable(
// Infinitely repeating a 1000ms tween animation using default easing curve.
animation = tween(1000),
// After each iteration of the animation (i.e. every 1000ms), the animation
// will
// start again from the [initialValue] defined above.
// This is the default [RepeatMode]. See [RepeatMode.Reverse] below for an
// alternative.
repeatMode = RepeatMode.Restart,
),
)
// Creates a Color animation as a part of the [InfiniteTransition].
val color by
infiniteTransition.animateColor(
initialValue = Color.Red,
targetValue = Color(0xff800000), // Dark Red
animationSpec =
infiniteRepeatable(
// Linearly interpolate between initialValue and targetValue every 1000ms.
animation = tween(1000, easing = LinearEasing),
// Once [TargetValue] is reached, starts the next iteration in reverse (i.e.
// from
// TargetValue to InitialValue). Then again from InitialValue to
// TargetValue. This
// [RepeatMode] ensures that the animation value is *always continuous*.
repeatMode = RepeatMode.Reverse,
),
)
Box(Modifier.fillMaxSize()) {
Icon(
Icons.Filled.Favorite,
contentDescription = null,
modifier =
Modifier.align(Alignment.Center).graphicsLayer(scaleX = scale, scaleY = scale),
tint = color,
)
}
}
}