MutableTransitionState


MutableTransitionState contains two fields: currentState and targetState. currentState is initialized to the provided initialState, and can only be mutated by a Transition. targetState is also initialized to initialState. It can be mutated to alter the course of a transition animation that is created with the MutableTransitionState using rememberTransition. Both currentState and targetState are backed by a State object.

import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.rememberTransition
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material.Card
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp

// This composable enters the composition with a custom enter transition. This is achieved by
// defining a different initialState than the first target state using `MutableTransitionState`
@Composable
fun PoppingInCard() {
    // Creates a transition state with an initial state where visible = false
    val visibleState = remember { MutableTransitionState(false) }
    // Sets the target state of the transition state to true. As it's different than the initial
    // state, a transition from not visible to visible will be triggered.
    visibleState.targetState = true

    // Creates a transition with the transition state created above.
    val transition = rememberTransition(visibleState)
    // Adds a scale animation to the transition to scale the card up when transitioning in.
    val scale by
        transition.animateFloat(
            // Uses a custom spring for the transition.
            transitionSpec = { spring(dampingRatio = Spring.DampingRatioMediumBouncy) }
        ) { visible ->
            if (visible) 1f else 0.8f
        }
    // Adds an elevation animation that animates the dp value of the animation.
    val elevation by
        transition.animateDp(
            // Uses a tween animation
            transitionSpec = {
                // Uses different animations for when animating from visible to not visible, and
                // the other way around
                if (false isTransitioningTo true) {
                    tween(1000)
                } else {
                    spring()
                }
            }
        ) { visible ->
            if (visible) 10.dp else 0.dp
        }

    Card(
        Modifier.graphicsLayer(scaleX = scale, scaleY = scale)
            .size(200.dp, 100.dp)
            .fillMaxWidth(),
        elevation = elevation
    ) {}
}

Summary

Public constructors

<S : Any?> MutableTransitionState(initialState: S)
Cmn

Public properties

open S

Current state of the transition.

Cmn
Boolean

isIdle returns whether the transition has finished running.

Cmn
open S

Target state of the transition.

Cmn

Public constructors

MutableTransitionState

<S : Any?> MutableTransitionState(initialState: S)

Public properties

currentState

open val currentState: S

Current state of the transition. currentState is initialized to the initialState that the MutableTransitionState is constructed with.

It will be updated by the Transition that is created with this MutableTransitionState when the transition arrives at a new state.

isIdle

val isIdleBoolean

isIdle returns whether the transition has finished running. This will return false once the targetState has been set to a different value than currentState.

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.ExperimentalTransitionApi
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.rememberTransition
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

@Composable
fun SelectableItem(selectedState: MutableTransitionState<Boolean>) {
    val transition = rememberTransition(selectedState)
    val cornerRadius by transition.animateDp { selected -> if (selected) 10.dp else 0.dp }
    val backgroundColor by
        transition.animateColor { selected -> if (selected) Color.Red else Color.White }
    Box(Modifier.background(backgroundColor, RoundedCornerShape(cornerRadius))) {
        // Item content goes here
    }
}

@OptIn(ExperimentalTransitionApi::class)
@Composable
fun ItemsSample(selectedId: Int) {
    Column {
        repeat(3) { id ->
            Box {
                // Initialize the selected state as false to produce a transition going from
                // false to true if `selected` parameter is true when entering composition.
                val selectedState = remember { MutableTransitionState(false) }
                // Mutate target state as needed.
                selectedState.targetState = id == selectedId
                // Now we pass the `MutableTransitionState` to the `Selectable` item and
                // observe state change.
                SelectableItem(selectedState)
                if (selectedState.isIdle && selectedState.targetState) {
                    // If isIdle == true, it means the transition has arrived at its target
                    // state
                    // and there is no pending animation.
                    // Now we can do something after the selection transition is
                    // finished:
                    Text("Nice choice")
                }
            }
        }
    }
}

targetState

open var targetState: S

Target state of the transition. targetState is initialized to the initialState that the MutableTransitionState is constructed with.

It can be updated to a new state at any time. When that happens, the Transition that is created with this MutableTransitionState will update its Transition.targetState to the same and subsequently starts a transition animation to animate from the current values to the new target.