メインコンテンツまでスキップ

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:

Android MotionLayout Example

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:

NumberLink
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!