How to Implement Motion Layout Animation in Android Studio
Motion Layout Animation is an essential feature in any application. It helps to improve the look and feel of the software. Animations promote user interactions.
For instance, when a user clicks a button, some animation may indicate that an action is performed. MotionLayout will be the focus of this tutorial, which is a layout that allows you to implement animations in your Android app quickly.
Introduction to MotionLayout
MotionLayout can be described as a layout that helps you to incorporate and manage animations in your application. This layout is a subclass of the ConstraintLayout. This means that it inherits ConstraintLayout’s rich features. ConstraintLayout allows MotionLayout support to older devices using API level 14.
Some of the animation styles that MotionLayout can implement are keyframes and seekable transitions. Keyframes enable you to customize transitions to fit your needs. On the other hand, seekable transitions allow you to jump at a particular point in the animation. One huge advantage of MotionLayout is that it’s fully declarative. This factor is quite critical, especially when building complex applications.
Goal
To implement animations in an Android application using MotionLayout.
What is MotionLayout?
MotionLayout is the new layout in Android, for creating amazing interactive animations in android. It’s a part of ConstraintLayout 2.0 library to help Android Developers manage motion and widget animation in their applications.
The MotionLayout widget can do everything the Constraint Layout widget can.
The main difference between ConstraintLayout and MotionLayout at the XML level is that the actual description of what MotionLayout will do is not necessarily contained in the layout file.Rather, MotionLayout typically keeps all this information in a separate XML file (a MotionScene
) that it references, and this information will take precedence over the information in the layout file.This way, the layout file can contain only the Views and their properties — not their positioning or movement.
Step 1 – Creating the project
Open Android studio and create a new project. Choose the Empty Activity
template since we will be building our layout from scratch. Click next
and choose API 14
as your minimum SDK. Remember to set your preferred programming language to Kotlin
. After completing these settings, click on finish
to allow the project to be initialized. Note that this process may take some considerable time depending on your computer speed and internet connection.
To have MotionLayout up and running in your project, and to get a feel of how it works, you’ll need:
- A starting layout that has the starting constraints
- An ending layout that has the ending constraints
- And a motion scene (which defines our animation)
Step 2 – Installing dependency
One key dependency that we need in our project is ConstraintLayout. Fortunately, it is included in all Android projects by default. Therefore, open the app-level build.gradle
file. In the dependency section, ensure that you are using a version of ConstraintLayout not less than 2.0.0
. This is demonstrated below.
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
Step 3 – Switching to MotionLayout
In this phase, we want to shift our default layout from ConstraintLayout to MotionLayout. This will allow us to access additional features such as transitions. Open the activity_main.xml file and switch from the code view to the design tab, as shown in the image below.
Step 4 – Adding UI components
We need to include some UI components in our applications to utilize MotionLayout. In this tutorial, we will be adding animation to a Button and ImageView. Copy and paste the following code snippets in the activity_main.xml
file to include these widgets in the app.
Step 5 – Animating the views
In the past, we were required to input transition values in the activity_main_scene.xml
file manually. This was quite cubersome and time-consuming. The introduction of Motion Layout Animation Editor in Android Studio 4.0 helped deal with these challenges.
Follow the below steps to use MotionLayout :
- Add ConstraintLayout 2.0 to your build.gradle dependencies
implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha2'
- Starting layout: This will the layout from where your animation will start. In my case the start activity is MotionStartActivity. Following is the code for the XML file activity_motion_start.xml. Just 3 views with constraints all set! Two of these will animate and third, will stay static.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.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/motion_scene">
<ImageView
android:id="@+id/movingImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/dog"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/button"
android:text="Slide Up to move dog towards the bone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:background="#EBA34B"
android:padding="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/staticImageView"
android:src="@drawable/bone"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.motion.MotionLayout>
- Ending Layout: We then create an ending layout, called activity_motion_end.xml.
Note: It only has the two views we intend to animate! (and their final constraints)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/movingImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/dog"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:id="@+id/button"
android:text="Slide Down to move dog away from bone"
android:background="#EBA34B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.motion.MotionLayout>
- Motion Scene: This is the file that defines the type of motion/animation we want and what the starting/ending constraints are. Let’s call it motion_scene.xml (placed in res/xml/motion_scene.xml)
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetStart="@layout/activity_motion_start"
motion:constraintSetEnd="@layout/activity_motion_end"
motion:duration="1000">
<OnSwipe
motion:touchAnchorId="@id/button"
motion:touchAnchorSide="top"
motion:dragDirection="dragUp"/>
</Transition>
</MotionScene>
Here we defined a Transition (the animation) with duration & a start/end point to the layouts. And also a swipe Trigger on the button (with up direction) — which adds interactivity.
Also, make sure to add a reference to this motion_scene file in activity_main using
app:layoutDescription="@xml/motion_scene"
And that's it! A simple motion layout animation is now added to the project.
Another Example (using KeyFrameSet)
Here we will use the KeyFrameSet for animation. KeyFrameSet is a child element of Transition and it can contain KeyPosition, KeyAttribute, and KeyCycle elements for defining middle states of animation.
- KeyPosition is used to add a position through which the target element passes when it is animated.
- KeyAttribute is used to add values for attributes for middle state. You can assign values for standard attributes by directly using the name of properties as attribute of KeyAttribute element.
- KeyCycle is used to add oscillations during Motion Layout Animation. You can specify the point on the animation at which you want oscillation by using framePosition attribute.
Let's take another example, whose Motion Scene file is :
<?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/wish_start"
motion:constraintSetEnd="@+id/wish_end"
motion:duration="2000">
<OnClick motion:target="@+id/click"/>
<KeyFrameSet>
<KeyPosition
motion:keyPositionType="pathRelative"
motion:percentY="0.25"
motion:framePosition="50"
motion:target="@id/tv1"/>
<KeyPosition
motion:keyPositionType="pathRelative"
motion:percentY="-0.25"
motion:framePosition="50"
motion:target="@id/tv2"/>
<KeyAttribute
motion:framePosition="50"
motion:target="@id/tv1"
android:rotation="-30"/>
<KeyAttribute
motion:framePosition="50"
motion:target="@id/tv2"
android:rotation="-30">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue ="20"/>
</KeyAttribute>
<KeyCycle
motion:framePosition="30"
motion:target="@id/tv1"
android:rotation="-30"
motion:waveShape="bounce"
motion:wavePeriod="3"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/wish_start">
<Constraint
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="hello"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue ="50"/>
</Constraint>
<Constraint
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="mindorks"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/tv1">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue ="50"/>
</Constraint>
<Constraint
android:id="@+id/click"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:text="click"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/wish_end">
<Constraint
android:id="@id/tv1"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="HELLO"
android:layout_marginTop="400dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue ="50"/>
</Constraint>
<Constraint
android:id="@id/tv2"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="MINDORKS"
android:layout_marginTop="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/tv1">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue ="50"/>
</Constraint>
<Constraint
android:id="@id/click"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:text="click"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>
The layout file for the above example is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:layout_marginTop="32dp"
app:layoutDescription="@xml/keyframeset">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="Hello"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toStartOf="@+id/tv2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="MindOrks"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv1"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/click"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click"
android:layout_marginTop="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.motion.MotionLayout>
Post a Comment
0Comments