Android Native - How to use MotionLayout

dimitrilc
Introduction

Among all of the animation API’s on Android, MotionLayout is one of the best classes to use to create complex animations. It can animate property and motion of multiple views at the same time. Other benefits include declarative style XML and the intuitive Motion Editor built right into Android Studio.

In this tutorial, we will learn how to move a drawable resource with MotionLayout.

Goals

At the end of the tutorial, you would have learned:

  1. How to set up MotionLayout.
  2. How to use the Motion Editor in Android Studio.
Prerequisite Knowledge
  1. Basic Android development knowledge.
Tools Required
  1. Android Studio.
Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.

  2. Delete the “Hello WorldTextView from activity_main.xml.

  3. Right-click on res/drawable -> New -> Vector Asset.

  4. Choose Clip Art as Asset Type.

  5. For the Name, use ic_android_black_100dp.

  6. For the Clip Art, find and select the android clip art.

  7. Set the size to 100x100.

  8. Use the default black color 000000.

  9. Opacity should be set to 100%.

  10. No need to check the TRL option.

  11. Select Next.
    Configure_Vector_Asset.png

  12. The icon path is under the default drawable directory at main/drawable/ic_android_black_100dp.xml
    confirm_icon_path.png

  13. Add a new ImageView below ConstraintView in activity_main.xml, selecting ic_android_black_100dp as the resource. If you do not want to use to the Design surface, the XML equivalence is:

     <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_android_black_100dp" />
  14. Click Finish.

MotionLayout subclasses ConstraintLayout

MotionLayout is a subclass of ConstraintLayout, so it is fine to replace ConstraintLayout with MotionLayout when you need to manage animation for child Views. We can safely convert the top level ConstraintLayout in activity_main.xml to a MotionLayout. The easiest way to do that is

  1. Open activity_main.xml in the Design surface.
  2. Right-click on ConstraintLayout.
  3. Convert to MotionLayout.
    Convert_to_motionlayout.png
  4. When prompted that the action will convert your layout into a MotionLayout and create a separate MotionScene file, select Convert.
    convert_confirm.png
  5. Right-click on activity_main.xml file -> Local History -> Show History. We can see that there are a total of 2 main changes.
    a. The ConstraintLayout has been replaced by the MotionLayout.
    b. The layout file additionally references another XML file. This activity_main_scene XML file contains the animation data, which we will discuss in the next section.

history.png

MotionScene

MotionLayout manages its own layout XML, but this XML only includes information for the child Views, and not animation data. Decoupling layout and animation code improves readability for your project. The XML containing the animation data is stored inside the activity_main_scene.xml file (for this tutorial) that Android Studio created earlier for us. If we look inside activity_main_scene.xml, we can see that there are quite a few tags inside.

  1. Transition: a nested class inside MotionScene that defines how the animations are triggered, the duration of the animations, and the animation trajectory.
  2. KeyFrameSet: all animations start with the starting constraint and end with the ending constraint. KeyFrameSet contains the key frames needed to modify the path of the animation. This is optional and is out of scope for this tutorial.
  3. ConstraintSet: specifies the constraints for Views inside a ConstraintLayout. The animation will start with the starting constraint and end with the ending constraint.
Motion Editor

If we open the activity_main.xml file now in the Design/Split surface, we can see that there is a new section called the Motion Editor. This tool allows us to modify the activity_main_scene.xml file with a graphical user interface and also to preview the animation.

MotionEditor.png

The starting Constraint

We need to create a starting constraint so that MotionLayout will know where the starting position would be. To do this with the Motion Editor, perform the following steps:

  1. Select the start constraint set.
    start.png

  2. Currently the imageView is still constrained to the Select Modify constraint set.
    imageView.png

  3. Create Constraint.
    create_constraint.png

  4. You will then see that the imageView is constrained to the starting constraint (with id of start).
    start_constraint.png

  5. The ConstraintSet inside activity_main_scene.xml is also modified accordingly.

     <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
     </ConstraintSet>
  6. We will want our imageView (android vector asset) to move from the bottom of the screen to the top of the screen, so add bottom, left and right constraints for it.

imageView_Constraint.png

The ending Constraint

Now that the starting point has been set, we will need to add the ending constraint. The steps are very similar to how we added the starting constraint in the previous section.

  1. Select the end ConstraintSet in the Motion Editor.
  2. Select the imageView in the Motion Editor.
  3. Select Modify constraint set.
  4. Create Constraint.
  5. Add top, left and right constraints to imageView.

ending_constraint.png

Animation Trigger

Since a Transition has already been defined for us in the activity_main_scene.xml file by Android Studio, we only need to add a trigger for our animation to start. We will use an onClick trigger for this part. To add a trigger, perform the steps below:

  1. Select the U-shaped arrow in the Motion Editor that connects the starting and ending constraint sets.
    arrow.png

  2. Select the Create click or swipe handler icon in the Motion Editor (highlited in yellow).
    clickhandler.png

  3. In View To Click, changes the value to imageView.

  4. Click Add.
    create_onclick.png

  5. Add an attribute called clickAction to the OnClick tag. The value for this attribute would be toggle. If you are confused about where this attribute came from. It is referenced here
    click_action.png

  6. The current XML definition for the OnClick tag would be:

     <OnClick motion:targetId="@+id/imageView"
        motion:clickAction="toggle" />
Preview the animation

One of the great features of Motion Editor is that you can preview the animation.

  1. Select the Transition element in Motion Editor (U-shaped arrow)
  2. When the Transition section shows up, press the Play button.

Transition_Preview.gif

Run the app

We have completed all of the steps required to animate the android icon. Go ahead and run the app. You will have to touch the icon once for the animation to start.

Android_Animation.gif

Solution Code

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
   android:layout_height="match_parent"
   app:layoutDescription="@xml/activity_main_scene"
   tools:context=".MainActivity">

   <ImageView
       android:id="@+id/imageView"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       app:srcCompat="@drawable/ic_android_black_100dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>

activity_mail_scene.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:constraintSetEnd="@+id/end"
       motion:constraintSetStart="@id/start"
       motion:duration="1000">
      <KeyFrameSet>
      </KeyFrameSet>
       <OnClick motion:targetId="@+id/imageView"
           motion:clickAction="toggle" />
   </Transition>

   <ConstraintSet android:id="@+id/start">
       <Constraint
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent"
           motion:layout_constraintEnd_toEndOf="parent" />
   </ConstraintSet>

   <ConstraintSet android:id="@+id/end">
       <Constraint
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintTop_toTopOf="parent"
           motion:layout_constraintEnd_toEndOf="parent" />
   </ConstraintSet>
</MotionScene>
Summary

Congratulations, you have learned how to use MotionLayout. The full project code can be found at https://github.com/dmitrilc/DaniwebMotionLayout/tree/main

254 Views
About the Author

My name is Dimitri Nguyen. I am a Java Developer specializing in backend development on the Java/Spring/MySQL stack.

I can also work on the frontend using Angular/Typescript/JS/HTML/CSS and native Android with Kotlin.

peter_budo 2,532 Code tags enforcer Team Colleague Featured Poster

Good article, but I would suggest to rename some of imageViewas it is not good practice to have multiple of same name in the the project ;)

commented: Thanks for the reminder. There is only one imageView View in this project though? +1
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts learning and sharing knowledge.