Creating Animations in XML Using MotionLayout

MotionLayout, a powerful layout type available in Android’s ConstraintLayout library, allows you to create complex animations and transitions in a declarative way using XML. This approach simplifies animation management compared to traditional code-based animations, making it easier to create engaging and interactive user interfaces.

What is MotionLayout?

MotionLayout is a layout type within the ConstraintLayout library that facilitates the creation of intricate animations and transitions by defining start and end states along with interpolation steps. It’s fully declarative, meaning that animations are described in XML rather than through imperative code, simplifying the design and maintenance of complex animations.

Why Use MotionLayout?

  • Declarative Animations: Define animations in XML, making them easier to manage and understand.
  • Complex Transitions: Create sophisticated transitions between different states of your layout.
  • Timeline Control: Precisely control animation behavior over time.
  • ConstraintLayout Integration: Leverage the power of ConstraintLayout for layout management and animation.

How to Create Animations in XML Using MotionLayout

To get started with MotionLayout, you’ll need to use the ConstraintLayout library and define your animations in XML.

Step 1: Add Dependency

Include the ConstraintLayout dependency in your app’s build.gradle file:


dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

Step 2: Create a MotionLayout XML File

Convert your layout to a MotionLayout XML file. To do this, right-click on your layout XML file in the `res/layout` directory, select “Convert to MotionLayout”. This will create a new file in the `res/xml` directory that defines your animation. Alternatively, you can create a MotionLayout from scratch directly in your layout file.

Here’s a basic example of a MotionLayout layout file (`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">

    <View
        android:id="@+id/myView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@color/colorPrimary"
        android:text="Hello MotionLayout"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_marginTop="50dp"
        android:layout_marginStart="50dp" />

</androidx.constraintlayout.motion.widget.MotionLayout>

Step 3: Create a Motion Scene File

The motion scene XML file (scene.xml in this example) describes the animation’s start and end states, as well as the transition that defines how the layout changes between these states.


<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        app:constraintSetStart="@+id/start"
        app:constraintSetEnd="@+id/end"
        app:duration="1000">

       <OnClick app:targetId="@+id/myView"
            app:clickAction="toggle" />

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/myView"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginTop="50dp"
            android:layout_marginStart="50dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/myView"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_marginTop="200dp"
            android:layout_marginEnd="200dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>

In this example:

  • <Transition>: Defines the animation between two constraint sets.
  • app:constraintSetStart: Specifies the starting constraint set.
  • app:constraintSetEnd: Specifies the ending constraint set.
  • app:duration: Defines the duration of the animation in milliseconds.
  • <OnClick>: Sets up a click listener to start the animation.
  • <ConstraintSet>: Defines the constraints for a particular state of the layout.

Step 4: Using KeyFrames

To add more intricate steps within the transition, KeyFrames are used.


<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <Transition
        app:constraintSetStart="@+id/start"
        app:constraintSetEnd="@+id/end"
        app:duration="1000">

       <OnClick app:targetId="@+id/myView"
            app:clickAction="toggle" />

        <KeyFrameSet>
            <KeyAttribute
                android:rotation="45"
                app:framePosition="50"
                app:motionTarget="@+id/myView" />
        </KeyFrameSet>

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/myView"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginTop="50dp"
            android:layout_marginStart="50dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/myView"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_marginTop="200dp"
            android:layout_marginEnd="200dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>

In this expanded example, inside the Transition, we added <KeyFrameSet> which defines an attribute modification at the middle of the transition.

  • <KeyAttribute> modifies properties like rotation, translationX, or scale during the transition.
  • app:framePosition: This attribute defines when the property changes occur. Values are between 0 (start) to 100 (end). In the sample above the view will rotate 45 degrees when the animation is at 50% complete.
  • app:motionTarget: Identifies which view should receive the transformation.

Advanced Features

1. Interpolation and Easing

You can define easing functions for smoother animation transitions by setting the motionInterpolator attribute in the Transition.


<Transition
    app:constraintSetStart="@+id/start"
    app:constraintSetEnd="@+id/end"
    app:duration="1000"
    app:motionInterpolator="easeInOut">
    ...
</Transition>

2. Custom Attributes

MotionLayout also allows the creation of custom attributes which allows properties to be assigned and modified that aren’t native view properties.

Conclusion

MotionLayout offers a powerful way to create animations and transitions in Android applications using XML. By leveraging constraint sets, transitions, and keyframes, developers can design complex animations declaratively, improving maintainability and readability of animation code. Whether it’s simple view movements or intricate state transitions, MotionLayout provides the necessary tools to make Android UIs engaging and dynamic.