MotionLayout

Functions summary

inline Unit
@ExperimentalMotionApi
@Composable
MotionLayout(
    motionScene: MotionScene,
    progress: Float,
    modifier: Modifier,
    transitionName: String,
    debugFlags: DebugFlags,
    optimizationLevel: Int,
    invalidationStrategy: InvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
)

Layout that can animate between multiple ConstraintSets as defined by Transitions in the given MotionScene.

inline Unit
@ExperimentalMotionApi
@Composable
MotionLayout(
    motionScene: MotionScene,
    constraintSetName: String?,
    animationSpec: AnimationSpec<Float>,
    modifier: Modifier,
    noinline finishedAnimationListener: (() -> Unit)?,
    debugFlags: DebugFlags,
    optimizationLevel: Int,
    invalidationStrategy: InvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
)

Layout that can animate between multiple ConstraintSets as defined by Transitions in the given MotionScene.

inline Unit
@ExperimentalMotionApi
@Composable
MotionLayout(
    start: ConstraintSet,
    end: ConstraintSet,
    progress: Float,
    modifier: Modifier,
    transition: Transition?,
    debugFlags: DebugFlags,
    optimizationLevel: Int,
    invalidationStrategy: InvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
)

Layout that can animate between two different layout states described in ConstraintSets.

Functions

@ExperimentalMotionApi
@Composable
inline fun MotionLayout(
    motionScene: MotionScene,
    progress: Float,
    modifier: Modifier = Modifier,
    transitionName: String = "default",
    debugFlags: DebugFlags = DebugFlags.None,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
): Unit

Layout that can animate between multiple ConstraintSets as defined by Transitions in the given MotionScene.

The animation is driven by the progress value, so it will typically be a result of using an Animatable or animateFloatAsState:

var animateToEnd by remember { mutableStateOf(false) }
MotionLayout(
motionScene = MotionScene {
val buttonRef = createRefFor("button")
defaultTransition(
from = constraintSet {
constrain(buttonRef) {
top.linkTo(parent.top)
}
},
to = constraintSet {
constrain(buttonRef) {
bottom.linkTo(parent.bottom)
}
}
)
},
progress = animateFloatAsState(if (animateToEnd) 1f else 0f).value,
modifier = Modifier.fillMaxSize()
)
{
Button(onClick = { animateToEnd = !animateToEnd }, Modifier.layoutId("button")) {
Text("Hello, World!")
}
}

Note that you must use Modifier.layoutId to bind the references used in the ConstraintSets to the Composable.

Parameters
motionScene: MotionScene

Holds all the layout states defined in ConstraintSets and the interpolation associated between them (known as Transitions).

progress: Float

Sets the interpolated position of the layout between the ConstraintSets.

modifier: Modifier = Modifier

Modifier to apply to this layout node.

transitionName: String = "default"

The name of the transition to apply on the layout. By default, it will target the transition defined with MotionSceneScope.defaultTransition.

debugFlags: DebugFlags = DebugFlags.None

Flags to enable visual debugging. DebugFlags.None by default.

optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD

Optimization parameter for the underlying ConstraintLayout, Optimizer.OPTIMIZATION_STANDARD by default.

invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy

Provides strategies to optimize invalidations in MotionLayout. Excessive invalidations will be the typical cause of bad performance in MotionLayout. See InvalidationStrategy to learn how to apply common strategies.

crossinline content: @Composable MotionLayoutScope.() -> Unit

The content to be laid out by MotionLayout, note that each layout Composable should be bound to an ID defined in the ConstraintSets using Modifier.layoutId.

@ExperimentalMotionApi
@Composable
inline fun MotionLayout(
    motionScene: MotionScene,
    constraintSetName: String?,
    animationSpec: AnimationSpec<Float>,
    modifier: Modifier = Modifier,
    noinline finishedAnimationListener: (() -> Unit)? = null,
    debugFlags: DebugFlags = DebugFlags.None,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
): Unit

Layout that can animate between multiple ConstraintSets as defined by Transitions in the given MotionScene.

The animation is driven based on the given constraintSetName. During recomposition, MotionLayout will interpolate from whichever ConstraintSet it currently is, to the one corresponding to constraintSetName. So, a null constraintSetName will result in no changes.

var name by remember { mutableStateOf(0) }
MotionLayout(
motionScene = MotionScene {
val buttonRef = createRefFor("button")
val initialStart = constraintSet("0") {
constrain(buttonRef) {
centerHorizontallyTo(parent, bias = 0f)
centerVerticallyTo(parent, bias = 0f)
}
}
val initialEnd = constraintSet("1") {
constrain(buttonRef) {
centerHorizontallyTo(parent, bias = 0f)
centerVerticallyTo(parent, bias = 1f)
}
}
constraintSet("2") {
constrain(buttonRef) {
centerHorizontallyTo(parent, bias = 1f)
centerVerticallyTo(parent, bias = 0f)
}
}
constraintSet("3") {
constrain(buttonRef) {
centerHorizontallyTo(parent, bias = 1f)
centerVerticallyTo(parent, bias = 1f)
}
}
// We need at least the default transition to define the initial state
defaultTransition(initialStart, initialEnd)
},
constraintSetName = name.toString(),
animationSpec = tween(1200),
modifier = Modifier.fillMaxSize()
) {
// Switch to a random ConstraintSet on click
Button(onClick = { name = IntRange(0, 3).random() }, Modifier.layoutId("button")) {
Text("Hello, World!")
}
}

Animations are run one after the other, if multiple are queued, only the last one will be executed. You may use finishedAnimationListener to know whenever an animation is finished.

Parameters
motionScene: MotionScene

Holds all the layout states defined in ConstraintSets and the interpolation associated between them (known as Transitions).

constraintSetName: String?

The name of the ConstraintSet to animate to. Null for no animation.

animationSpec: AnimationSpec<Float>

Specifies how the internal progress value is animated.

modifier: Modifier = Modifier

Modifier to apply to this layout node.

noinline finishedAnimationListener: (() -> Unit)? = null

Called when an animation triggered by a change in constraintSetName has ended.

debugFlags: DebugFlags = DebugFlags.None

Flags to enable visual debugging. DebugFlags.None by default.

optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD

Optimization parameter for the underlying ConstraintLayout, Optimizer.OPTIMIZATION_STANDARD by default.

invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy

Provides strategies to optimize invalidations in MotionLayout. Excessive invalidations will be the typical cause of bad performance in MotionLayout. See InvalidationStrategy to learn how to apply common strategies.

crossinline content: @Composable MotionLayoutScope.() -> Unit

The content to be laid out by MotionLayout, note that each layout Composable should be bound to an ID defined in the ConstraintSets using Modifier.layoutId.

@ExperimentalMotionApi
@Composable
inline fun MotionLayout(
    start: ConstraintSet,
    end: ConstraintSet,
    progress: Float,
    modifier: Modifier = Modifier,
    transition: Transition? = null,
    debugFlags: DebugFlags = DebugFlags.None,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy,
    crossinline content: @Composable MotionLayoutScope.() -> Unit
): Unit

Layout that can animate between two different layout states described in ConstraintSets.

The animation is driven by the progress value, so it will typically be a result of using an Animatable or animateFloatAsState:

var animateToEnd by remember { mutableStateOf(false) }
MotionLayout(
start = ConstraintSet {
constrain(createRefFor("button")) {
top.linkTo(parent.top)
}
},
end = ConstraintSet {
constrain(createRefFor("button")) {
bottom.linkTo(parent.bottom)
}
},
progress = animateFloatAsState(if (animateToEnd) 1f else 0f).value,
modifier = Modifier.fillMaxSize()
)
{
Button(onClick = { animateToEnd = !animateToEnd }, Modifier.layoutId("button")) {
Text("Hello, World!")
}
}

Note that you must use Modifier.layoutId to bind the references used in the ConstraintSets to the Composable.

Parameters
start: ConstraintSet

ConstraintSet that defines the layout at 0f progress.

end: ConstraintSet

ConstraintSet that defines the layout at 1f progress.

progress: Float

Sets the interpolated position of the layout between the ConstraintSets.

modifier: Modifier = Modifier

Modifier to apply to this layout node.

transition: Transition? = null

Defines the interpolation parameters between the ConstraintSets to achieve fine-tuned animations.

debugFlags: DebugFlags = DebugFlags.None

Flags to enable visual debugging. DebugFlags.None by default.

optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD

Optimization parameter for the underlying ConstraintLayout, Optimizer.OPTIMIZATION_STANDARD by default.

invalidationStrategy: InvalidationStrategy = InvalidationStrategy.DefaultInvalidationStrategy

Provides strategies to optimize invalidations in MotionLayout. Excessive invalidations will be the typical cause of bad performance in MotionLayout. See InvalidationStrategy to learn how to apply common strategies.

crossinline content: @Composable MotionLayoutScope.() -> Unit

The content to be laid out by MotionLayout, note that each layout Composable should be bound to an ID defined in the ConstraintSets using Modifier.layoutId.