{% setvar book_path %}/reference/androidx/_book.yaml{% endsetvar %} {% include "_shared/_reference-head-tags.html" %}

TransitionKt

public final class TransitionKt


Summary

Public methods

static final @NonNull State<@NonNull Color>
@Composable
<S extends Object> animateColor(
    @NonNull Transition<@NonNull S> receiver,
    @Composable @ExtensionFunctionType @NonNull Function1<@NonNull Transition.Segment<@NonNull S>, @NonNull FiniteAnimationSpec<@NonNull Color>> transitionSpec,
    @NonNull String label,
    @Composable @NonNull Function1<@NonNull state, @NonNull Color> targetValueByState
)

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

static final @NonNull State<@NonNull Color>
@Composable
animateColor(
    @NonNull InfiniteTransition receiver,
    @NonNull Color initialValue,
    @NonNull Color targetValue,
    @NonNull InfiniteRepeatableSpec<@NonNull Color> animationSpec,
    @NonNull String label
)

Creates a Color animation that runs infinitely as a part of the given InfiniteTransition.

Public methods

animateColor

@Composable
public static final @NonNull State<@NonNull Color> <S extends Object> animateColor(
    @NonNull Transition<@NonNull S> receiver,
    @Composable @ExtensionFunctionType @NonNull Function1<@NonNull Transition.Segment<@NonNull S>, @NonNull FiniteAnimationSpec<@NonNull Color>> transitionSpec,
    @NonNull String label,
    @Composable @NonNull Function1<@NonNull state, @NonNull Color> targetValueByState
)

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.

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.Transition
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.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp

// 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)
    )
}
Returns
@NonNull State<@NonNull Color>

A State object, the value of which is updated by animation

animateColor

@Composable
public static final @NonNull State<@NonNull ColoranimateColor(
    @NonNull InfiniteTransition receiver,
    @NonNull Color initialValue,
    @NonNull Color targetValue,
    @NonNull InfiniteRepeatableSpec<@NonNull Color> animationSpec,
    @NonNull String label
)

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.

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer

@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
        )
    }
}