Skip to content

Compose MotionLayout DSL Syntax

Oscar Adame Vazquez edited this page Sep 22, 2022 · 4 revisions

Added first in 1.1.0-alpha04.

Overview

MotionScene

The MotionScene takes a collection of ConstraintSets and Transitions.

Each ConstraintSet represents a specific Layout and each Transition represents the animation description between two ConstraintSets.

So the most basic MotionLayout requires two ConstraintSets and a default Transition that defines the initial state.

MotionLayout(
    MotionScene { // this: MotionSceneScope
        val textRef = createRefFor("text")
        defaultTransition(
            from = constraintSet { // this: ConstraintSetScope
                constrain(textRef) { // this: ConstrainScope
                    bottom.linkTo(parent.bottom)
                    start.linkTo(parent.start)
                }
            },
            to = constraintSet { // this: ConstraintSetScope
                constrain(textRef) { // this: ConstrainScope
                    top.linkTo(parent.top)
                    end.linkTo(parent.end)
                }
            }
        ) { // this: TransitionScope
            onSwipe = OnSwipe(
                anchor = textRef,
                side = SwipeSide.End,
                direction = SwipeDirection.End,
                mode = SwipeMode.Spring,
                onTouchUp = SwipeTouchUp.AutoComplete
            )
        }
    },
    progress = 0f,
    Modifier.fillMaxSize()
) {
    Text("Hello, World", Modifier.layoutId("text"))
}

Adding Existing ConstraintSets

All ConstraintSets and Transitions must be defined within the scope of the MotionScene. You may add existing ConstraintSet or Transition objects with addConstraintSet and addTransition respectively.

Note that the name given to the ConstraintSets should match the names defined in the Transition.

val cSet1 = ConstraintSet { }
val cSet2 = ConstraintSet { }
val transition = Transition(from = "start", to = "end") { }
MotionScene {
    addConstraintSet(name = "start", cSet1)
    addConstraintSet(name = "end", cSet2)
    addTransition(name = "default", transition)
}

Transition

OnSwipe

Defining the onSwipe allows you to control the animation progress with gestures.

The most basic OnSwipe requires the anchor to track, direction and side of the Swipe.

Transition {
    val boxRef = createRefFor("box")
    onSwipe = OnSwipe(
        anchor = boxRef,
        side = SwipeSide.Middle,
        direction = SwipeDirection.Up
    )
}

Parameters

  • anchor: ConstrainedLayoutReference - The Composable you wish your finger to track
  • side: SwipeSide - The side of the anchor Composable your finger will track
  • direction: SwipeDirection - direction of you motion
  • dragScale: Float - a scale factor to magnify your motion
  • dragThreshold: Float - Minimum drag distance
  • dragAround: ConstrainedLayoutReference? -
  • limitBoundsTo: ConstrainedLayoutReference? -
  • onTouchUp: SwipeTouchUp = SwipeTouchUp.AutoComplete - What happens on lifting your finger
  • mode: SwipeMode - Spring or Velocity mode

SwipeMode

Defines the animation of the swipe after lifting your finger. It may be either Velocity or Spring.

Note that each mode has its own parameters.

Velocity

fun Velocity(
    maxVelocity: Float = 4f,
    maxAcceleration: Float = 1.2f
)

Spring

fun Spring(
    mass: Float = 1f,
    stiffness: Float = 400f,
    damping: Float = 10f,
    threshold: Float = 0.01f,
    boundary: SpringBoundary = SpringBoundary.Overshoot
)

KeyFrames

You may define KeyAttributes, KeyPositions and KeyCycles.

With each type of KeyFrame you must indicate which widgets its referencing at its values at different positions of the progress (from 0 to 100).

For example:

Transition {
    val imgRef = createRefFor("img")
    keyAttributes(imgRef) {
        // Rotate 45 degrees left at 25% of the progress
        frame(25) {
            rotationZ = -45f
        }

        // Rotate 45 degrees right at 75% of the progress
        frame(75) {
            rotationZ = 45f
        }
    }
}

ConstraintSet

See ConstraintSet DSL.