At Google I/O 2018,
MotionLayout was announced promising to ease difficulty for developers when creating complex animations. Recently, at Android Dev Summit 2019, the Android Studio and
MotionLayout teams showed off a new
MotionEditor tool that aims to even further simplify creating complex animations with
MotionLayout. We are going to explore both during this post.
We are going to work on an animation that transitions a search box for a destination to two search boxes for both destination and origin locations.
Download Android Studio 4.0 Preview and add dependencies
To take advantage of the new
MotionEditor features within Android Studio, we will need to download the latest
Starting from a new “Empty Activity” project, we need to open our
app/build.gradle to add the dependency needed for
dependencies implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3' ...
MotionLayout is actually a
ConstraintLayout which allows us to animate layouts between various states.
Creating a new
We can now open the
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
We can see that with the project template, Android Studio has already generated a
ConstraintLayout which we can use to convert to
MotionLayout. With the layout file open, look for a new set of buttons in the top right of Android Studio and click the
With this viewing mode selected, we can now right-click on
ConstraintLayout in the
Component Tree section and click “Convert to MotionLayout”:
Android Studio is going to convert our
MotionLayout, generate a
MotionScene file (
res/xml/activity_main_scene.xml), and display the new Motion Editor tooling that will let us build our animations.
<?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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.motion.widget.MotionLayout>
Note: the conversion automatically added the attribute
app:layoutDescription="@xml/activity_main_scene" to our
MotionLayout, which links it to our
Add UI Components
For this example, we want to create a swipe-able sheet with two
EditTexts and a
FloatingActionButton. Before we start working on the
MotionScene that will coordinate and animate the UI, we need to add the components to our
activity_main.xml (there are
Drawable resources referenced here that you will need to add from this project):
Note: We didn’t add constraints to the views in this layout file. Views that are animated should have their constraints set in the motion scene file instead.
If a view should not be animated, its constraints should be set in the layout XML file. We also did not include any attributes that adjust visibility or opacity. We will see in just a moment how these attributes are controlled and adjusted in the
Define UI Constraints
Now that we have our UI components added to our
activity_main.xml, we can shift focus to
activity_main_scene.xml where we will work on adding two
ConstraintSets to define a “start” and “end” of our
MotionScene. Let’s start by visually defining how we would like to organize the UI before and after the animation.
If we open up
activity_main_scene.xml, we can see that when we converted our
ConstraintLayout to a
MotionLayout, Android studio generated a start and end
ConstraintSet for us, but left it empty:
<MotionScene> <Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@id/start" motion:duration="1000"> ... </Transition> <ConstraintSet android:id="@+id/start"> </ConstraintSet> <ConstraintSet android:id="@+id/end"> </ConstraintSet> </MotionScene>
Now we can define our
Add swipe handling for bottom sheet
One of the first updates we can make to our
Transition is the ability to handle user interaction to start our animation. Fortunately, with
MotionLayout, we can add handling right in the
activity_main_scene.xml with a few lines of code:
<Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@id/start" motion:duration="2000"> <OnSwipe motion:dragDirection="dragUp" motion:touchAnchorId="@id/bottomSheet" motion:touchRegionId="@id/bottomSheet" /> ... </Transition>
OnSwipe with the defined
touchRegionId we will now be able to handle a user swiping on our bottom sheet. Note here that the
touchRegionId allows us to scope the swipe handling to just the bottom sheet
View. This way, users can still interact with the map behind the bottom sheet.
Define KeyFrames for KeyFrameSet
Constraints defined, we get to tackle the fun part – let’s use the new
MotionEditor to define our
KeyFrameSet within the
Transition. We can open
activity_main.xml again and make sure we have the “Design” tab clicked in the top right corner.
Let’s work on our
FloatingActionButton first. As the bottom sheet expands, we can add
KeyFrames to animate the button off of the screen to the right:
To achieve this, we are going to add two
KeyFrames with the
MotionEditor. The first, to adjust the button’s
alpha (notice how it fades) and the second to adjust the position of the button.
Let’s make sure we have our
activity_main.xml open with the
Design button selected. We also want to have the
Transition panel open in the bottom right window. Click the arrow in between the start and end screen if this isn’t showing:
We can then click the icon in the top right of the
We can then click
KeyAttribute > ID:
fabMyLocation > Position:
20 > Attribute:
Let’s repeat the same process with
KeyPosition > ID:
fabMyLocation > Position:
20 > Type:
parentRelative (take a look at this post) for more on position type) > Percent X:
1.2. After we’ve added both of these KeyFrames, we can take a look at
activity_main_scene.xml and see where these have automatically been added:
<KeyFrameSet> <KeyPosition motion:framePosition="20" motion:keyPositionType="parentRelative" motion:motionTarget="@+id/fabMyLocation" motion:percentX="1.2" /> <KeyAttribute android:alpha="0.0" motion:framePosition="20" motion:motionTarget="@+id/fabMyLocation" /> ... </KeyFrameSet>
Note: we have adjusted the
0.0 as we want the
FloatingActionButton to be invisible by frame 20 of the
At this point, although we haven’t added the
KeyFrames for our
EditTexts, let’s build our app and try it out with just the button animation.
We can now finish the rest of the
KeyFrames for the origin and destination
EditTexts. We want the origin to be hidden until the animation has finished as well as the origin and destination icons. We also want the search icon to fade as it is replaced with the origin and destination icons. Try adding these
KeyFrames yourself – if you get stuck, reference the finished scene code below.
One great thing about the
MotionEditor is that it allows you to preview and fine-tune your
KeyFrames without having to rebuild the app each time:
Build the app and check out your finished animation!
MotionLayout now combined with the new
MotionEditor Android Studio tooling makes it much easier to create complex animations for your project.