Locomotion with Motion Layout

Ivana Tanova
4 min readNov 25, 2019

What you will learn:

  1. How to add simple animation.
  2. How to decorate the animation.
  3. How to rotate, scale and move a view.
  4. How to animate custom property — background color.

You can find the end project here:

  1. Set up

MotionLayout is subclass of ConstraintLayout. As part of Constraint Layout library it is backward-compatable to API level 14.

To use it you need to import Constraint Layout 2.0.0-beta1 version.

dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
}

2. Create a project

Create a Simple Activity Android Studio project. Then change main_activity.xml ConstraintLayout to MotionLayout (Remember Motion Layout is its subclass). Now include the two images that we will animate.

<ImageView
android:id="@+id/locomotion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/train" />

<ImageView
android:id="@+id/sun"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/sun" />

As you see they don’t have constraints specified. When using MotionLayout constraints are descibed in xml file that is later associated to the used MotionLayou. Let’s do this. Create folder xml and a file inside — motion_scene.xml.

3. Create Motion Scene

All animations are described in motion_scene.xml. We don’t use other code for that. Now create MotionScene element as a root element.

<?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">

Here we will describe the start position of our elements, and what end position we want at the end of the animation. This is done in ConstraintSet elements. You always have two ConstraintSet-one that describes the start position and one that describes the end poition. Let’s do this:

<ConstraintSet android:id="@+id/start">

<Constraint
android:id="@+id/locomotion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">

<Constraint
android:id="@+id/locomotion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent" />
</ConstraintSet>

Here we’ve described that locomotion image will be set to the bottom of the view but at the beginning of the animation we want its start position to align with start position of the parent but when animation has finished we want end of the locomotion aligned with the end of the parent. This is almost all we should do to have a nice smooth animation for horizontal movement of an element.

Now associate that MotionScene with our MotionLayout. Add in main_activity.xml :

<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layoutDescription="@xml/motion_scene"
tools:context=".MainActivity"
tools:showPaths="true">

Run the project. . Oops nothing is animated! :(

We forgot to describe which ConstraintSet is for start and which for end. Add element Transition above ConstraintSets definitions and specify:

<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"

motion:duration="5000">

We also must specify when animation should start. Let’s say we want that when locomotion view is clicked.

<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"
motion:duration="5000">

<OnClick
motion:clickAction="toggle"
motion:targetId="@id/locomotion"
/>

Run the project again and click the locomotion view. Let’s do the locomotion.

For homework try to add the sun and do the horizontal movement animation by yourself. Hint: It`s almost the same exept start position, end position and top positions :D

4. Alternate the animation at some point

For now we have smooth linear animation from the start to the end…Booring.. We want our train to move like a real one. Our key is to use elements KeyPosition. Key position elements are used to specify a change, at a given time during the interpolation between two states.

Add KeyPosition inside of the motion_scene.xml- Transition element:

<KeyPosition
motion:framePosition="25"
motion:keyPositionType="pathRelative"
motion:motionTarget="@id/locomotion"
motion:percentX="0.75"
motion:percentY="-0.3" />

What are the elements inside:

  • framePosition — percent of the animation that have passed when we want the event to happen
  • keyPositionType — the coordinate system used
  • motionTarget — which elment we will move
  • percentX — movement on the x axis
  • percentY — movement on the y axis

We will need some more to represent spiral train path. KeyPostion elements must be inside KeyFrameSet element

<KeyFrameSet>
<!-- Let's do the locomotion -->
<KeyPosition
motion:framePosition="25"
motion:keyPositionType="pathRelative"
motion:motionTarget="@id/locomotion"
motion:percentX="0.75"
motion:percentY="-0.3" />
<KeyPosition
motion:framePosition="50"
motion:keyPositionType="pathRelative"
motion:motionTarget="@id/locomotion"
motion:percentY="-0.4" />
<KeyPosition
motion:framePosition="75"
motion:keyPositionType="pathRelative"
motion:motionTarget="@id/locomotion"
motion:percentX="0.25"
motion:percentY="-0.3" />
</KeyFrameSet>

Remember this is all we need to create an animation. For homework — define sun path as an arc not linear path. Hint: You will need to alternate sun’s path at the middle of the animation and the alternation won’t be on the x axis as it was with the locomotion’s path. Another hint: use negative percents as the sun needs to decline

5. Alternate animated element attribute

We want the sun to rotate and smile. So we need a KeyAttribute element.

Key attribute elements are used to alternate attribute of the animated object. In our case this will be rotation attribute. Let’s add the elements.

<KeyFrameSet>
<KeyAttribute
android:rotation="-360"
motion:framePosition="50"
motion:motionTarget="@id/sun" />
<KeyAttribute
android:rotation="-720"
motion:framePosition="100"
motion:motionTarget="@id/sun" />
</KeyFrameSet>

Elements are:

  • framePosition — same as KeyPosition’s one
  • motionTarget — same as KeyPosition’s one
  • rotataion — this attribute we want to alternate

Supported attributes are:

android:visibility, android:alpha, android:elevation, android:rotation, android:rotationX, android:rotationY, android:scaleX, android:scaleY, android:translationX, android:translationY, android:translationZ

Homework: change the scale attribute of the sun. Hint: You can insert it in the same KeyAttribute elements.

6. Animate custom attribute

There are attributes that are not supported out of the box as the backgroundColor. To animate them we also use KeyAttribute elements, but inside we include element CustomAttribute. Here is the code:

<KeyFrameSet>
<KeyAttribute
motion:framePosition="0"
motion:motionTarget="@id/background">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#d7f0f7" />

</KeyAttribute>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/background">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#5ad1f2" />

</KeyAttribute>

<KeyAttribute
motion:framePosition="75"
motion:motionTarget="@id/background">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#064152" />

</KeyAttribute>
</KeyFrameSet>
  • attributeName — as you may guess — the name of the attribute
  • customColorValue — wanted color

We also have customIntegerValue , customFloatValue and etc.

Homework — Research Easing and KeyCycle elements to add acceleration to the train and bounce to that rock:

Happy codding!

--

--

Ivana Tanova

Android enthusiast and keen tea drinker. I love to learn and to be funny, both for me are passions.