Android Studio

Manage motion and widget animation with MotionLayout

Try the Compose way
Jetpack Compose is the recommended UI toolkit for Android. Learn how to use animations in Compose.

MotionLayout is a layout type that helps you manage motion and widget animation in your app. MotionLayout is a subclass of ConstraintLayout and builds on its rich layout capabilities. As part of the ConstraintLayout library, MotionLayout is available as a support library.

MotionLayout bridges the gap between layout transitions and complex motion handling, offering a mix of features between the property animation framework, TransitionManager, and CoordinatorLayout.

Figure 1. Basic touch-controlled motion.

In addition to describing transitions between layouts, MotionLayout lets you animate any layout properties. Moreover, it inherently supports seekable transitions. This means you can instantly show any point within the transition based on some condition, such as touch input. MotionLayout also supports keyframes, enabling fully customized transitions to suit your needs.

MotionLayout is fully declarative, meaning you can describe any transitions in XML, no matter how complex.

Design considerations

MotionLayout is intended to move, resize, and animate UI elements with which users interact, such as buttons and title bars. Don't use motion in your app as a gratuitous special effect. Use it to help users understand what your app is doing. For more information about designing your app with motion, see the Material Design section Understanding motion.

Get started

Follow these steps to start using MotionLayout in your project.

  • Add the ConstraintLayout dependency: to use MotionLayout in your project, add the ConstraintLayout 2.0 dependency to your app's build.gradle file. If you're using AndroidX, add the following dependency:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.1"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1"
    }

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
    }
  • Create a MotionLayout file: MotionLayout is a subclass of ConstraintLayout, so you can transform any existing ConstraintLayout into a MotionLayout by replacing the class name in your layout resource file, as shown in the following examples:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    Support library

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    Here's a full example of a MotionLayout file, which defines the layout shown in figure 1:

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    Support library

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  • Create a MotionScene: in the previous MotionLayout example, the app:layoutDescription attribute references a motion scene. A motion scene is an XML resource file. Within its <MotionScene> root element, a motion scene contains all the motion descriptions for the corresponding layout. To keep layout information separate from motion descriptions, each MotionLayout references a separate motion scene. The definitions in the motion scene take precedence over any similar definitions in the MotionLayout.

    Here's an example motion scene file that describes the basic horizontal motion in figure 1:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    Note the following:

  • <Transition> contains the base definition of the motion.

  • <OnSwipe> lets you create touch control for the motion.

  • <ConstraintSet> is where you define the various constraints that describe your motion. In this example, one <ConstraintSet> is defined for each endpoint of your motion. These endpoints are centered vertically using app:layout_constraintTop_toTopOf="parent" and app:layout_constraintBottom_toBottomOf="parent". Horizontally, the endpoints are at the far left and right sides of the screen.

    For a more detailed look at the various elements that a motion scene supports, see the MotionLayout examples.

    Interpolated attributes

    Within a motion scene file, ConstraintSet elements can contain additional attributes that are interpolated during transition. In addition to position and bounds, the following attributes are interpolated by MotionLayout:

    Custom attributes

    Within a <Constraint>, you can use the <CustomAttribute> element to specify a transition for attributes that aren't simply related to position or View attributes.

    <Constraint
        android:id="@+id/button" ...>
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60"/>
    </Constraint>

    A <CustomAttribute> contains two attributes of its own:

    When specifying a custom attribute, define endpoint values in both the start and end <ConstraintSet> elements.

    Change background color

    Building on the previous example, suppose you want the view's colors to change as part of its motion, as shown in figure 2.

    Figure 2. The view changes its background color as it moves.

    Add a <CustomAttribute> element to each ConstraintSet elements, as shown in the following code snippet:

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent">
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="#D81B60" />
        </Constraint>
    </ConstraintSet>
    
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent">
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="#9999FF" />
        </Constraint>
    </ConstraintSet>

    Additional MotionLayout attributes

    In addition to the attributes in the preceding example, MotionLayout has other attributes you might want to specify:

    Additional resources

    For more information about MotionLayout, see the following resources: