MotionLayout in Android - A Comprehensive Guide
If you're an Android developer, you've probably heard of ConstraintLayout. It's a powerful layout manager that allows you to create complex layouts with ease. But have you heard of MotionLayout? It's an extension of ConstraintLayout that adds powerful animation capabilities. In this article, we'll explore MotionLayout and how you can use it to create beautiful animations in your Android apps.
What is MotionLayout?
MotionLayout is an extension of ConstraintLayout that allows you to create complex animations with minimal code. It's a powerful tool that can help you create animations that would otherwise be difficult or impossible to achieve. With MotionLayout, you can create animations that involve multiple views, transitions, and keyframes.
How does MotionLayout work?
MotionLayout works by allowing you to define keyframes that describe the state of your layout at different points in time. You can then define transitions between these keyframes, which describe how your layout should change from one state to another. These transitions can involve changes to the position, size, rotation, and other properties of your views.
Getting started with MotionLayout
To get started with MotionLayout, you'll need to add the following dependency to your app's build.gradle file:
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
Once you've added the dependency, you can start using MotionLayout in your layouts. To create a MotionLayout, you'll need to replace your existing ConstraintLayout with a MotionLayout:
<androidx.constraintlayout.motion.widget.MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your views go here -->
</androidx.constraintlayout.motion.widget.MotionLayout>
Next, you'll need to define your keyframes and transitions. You can do this in an XML file, which you'll reference in your MotionLayout:
<?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">
<!-- Your keyframes go here -->
</Transition>
<ConstraintSet android:id="@+id/start">
<!-- Define the initial state of your layout -->
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<!-- Define the final state of your layout -->
</ConstraintSet>
</MotionScene>
In this XML file, you'll define a Transition that describes how your layout should transition from the start state to the end state. You'll also define ConstraintSets that describe the initial and final states of your layout. You can then define your keyframes within the Transition, using the following syntax:
<KeyFrame
motion:framePosition="0"
motion:target="@id/view">
<!-- Define the properties of your view at this keyframe -->
</KeyFrame>
In this example, we're defining a keyframe with a framePosition of 0 (i.e. the start of the animation), and we're targeting a view with an ID of "view". You can then define the properties of your view at this keyframe, such as its position, size, and rotation.
Examples
Let's take a look at a few examples of what you can do with MotionLayout.
1. Collapsing Toolbar
One of the most common uses for MotionLayout is to create a collapsing toolbar. Here's an example of how you can achieve this with MotionLayout:
<androidx.constraintlayout.motion.widget.MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/collapsing_toolbar_scene">
<ImageView
android:id="@+id/header_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/header_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My Title"
android:textSize="18sp"
app:layout_constraintTop_toBottomOf="@id/header_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- Your content goes here -->
</androidx.constraintlayout.motion.widget.MotionLayout>
In this example, we're using a MotionLayout with a layoutDescription that defines a collapsing toolbar. We have an ImageView at the top of the layout that serves as our header image, and a TextView below it that displays the title of our content. The content itself goes below the TextView.
2. Swipe to Dismiss
Another common use for MotionLayout is to create a swipe-to-dismiss animation. Here's an example of how you can achieve this with MotionLayout:
<androidx.constraintlayout.motion.widget.MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/swipe_to_dismiss_scene">
<View
android:id="@+id/background_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_color"/>
<TextView
android:id="@+id/content_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Swipe to dismiss"
android:textSize="18sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
In this example, we're using a MotionLayout with a layoutDescription that defines a swipe-to-dismiss animation. We have a background view that covers the entire layout and has a background color, and a TextView that displays our content. When the user swipes the TextView to the right, it disappears off the screen and the background view is revealed.
Examples
In this next section you will learn by looking at examples of how to use it to manage animations in your app.
What is MotionLayout?
But first what is it?
MotionLayout is a layout type that helps you manage motion and widget animation in your app.
This class subclasses and builds upon the flexible ConstraintLayout. It is thus available starting from API level 14. It bridges the gap between layout transitions and complex motion handling, offering a mix of features between the property animation framework, TransitionManager, and CoordinatorLayout.
You can read more about motionlayout here.
Example 1: MotionLayout - Parallax Scrolling using MotionLayout
This is a simple example that introduces you to motionlayout by implementing Parallax scrolling effect on content.
This is important especially on detail pages to provide a modern experience to users. Here's a demonstration of what is being built:

Step 1: Dependencies
No third party dependency is needed for this project.
Step 2: Define Motions
You need to define motions as xml resource files. First create folder known as xml under your res directory and add the following two scenes:
scene_header.xml
In this file define a root MotionScene element:
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
....
Define a transition, passing in the start, the end as well as duration:
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000"
motion:motionInterpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/image"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragUp"/>
Here's the full code:
<?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"
motion:motionInterpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/image"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragUp"/>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@id/image"
android:layout_width="match_parent"
android:layout_height="220dp"
android:alpha="1.0"
motion:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@+id/guideline"
motion:layout_constraintStart_toStartOf="parent"/>
<Constraint
android:id="@id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
motion:layout_constraintGuide_begin="210dp"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@id/image"
android:layout_width="match_parent"
android:layout_height="220dp"
android:alpha="0"
android:translationX="0dp"
android:translationY="0dp"
motion:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="0.6"
android:scaleY="0.6"
motion:layout_constraintBottom_toBottomOf="@+id/guideline"
motion:layout_constraintStart_toStartOf="parent"/>
<Constraint
android:id="@id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
motion:layout_constraintGuide_begin="56dp"/>
</ConstraintSet>
</Transition>
</MotionScene>
scene_main.xml
<?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="300"
motion:motionInterpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/header"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragUp" />
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@id/header"
android:layout_width="match_parent"
android:layout_height="220dp"
motion:layout_constraintTop_toTopOf="parent" />
<Constraint
android:id="@id/contents"
android:layout_width="match_parent"
android:layout_height="0dp"
motion:layout_constraintTop_toBottomOf="@+id/header"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="56dp"
motion:layout_constraintTop_toTopOf="parent"
motion:progress="1"/>
<Constraint
android:id="@id/contents"
android:layout_width="match_parent"
android:layout_height="0dp"
motion:layout_constraintTop_toBottomOf="@+id/header"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
</Transition>
</MotionScene>
Step 3: Create Layouts
The next step is to create your xml layouts. There are three such layouts:
(a). header_scroll.xml
The root element in this layout will be the MotionLayout:
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
app:layoutDescription="@xml/scene_header">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="220dp"
android:scaleType="centerCrop"
android:src="@drawable/flower"/>
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lorem Ipsum"
android:textSize="30dp"
android:padding="10dp"
android:textColor="#FFFFFF"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="210dp"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
(b). contents_scroll.xml
In the content, place a textview inside a NestedScrollView, this will be the widget to show the details content:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/contents"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/large_text"
android:padding="10dp"/>
</androidx.core.widget.NestedScrollView>
(c). activity_main.xml
This is a simple layou. Simply include the header_scroll and content_scroll inside a MotionLayout in this layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene_main"
tools:context=".MainActivity">
<include layout="@layout/header_scroll"/>
<include layout="@layout/contents_scroll"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Step : Write Code
The next step is to write your MainActivity code, in this case in Kotlin Programming language. This will be your launcher activity.
Here's the full code:
MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Step : Run Code
Afetr following the abobe steps run the code in android studio. Scroll above to the description of this project to see the result.
Reference
You can find the download links to the project below:
| Number | Link |
|---|---|
| 1. | Download code |
| 2. | Follow code author |
Conclusion
MotionLayout is a powerful tool that allows you to create complex animations with minimal code. With MotionLayout, you can create animations that involve multiple views, transitions, and keyframes. In this article, we've explored MotionLayout and how you can use it to create beautiful animations in your Android apps. We've looked at examples of how to create a collapsing toolbar and a swipe-to-dismiss animation, but the possibilities are endless. Try using MotionLayout in your next project and see what kind of animations you can create!