Building SwipeView using MotionLayout

Balarka Velidi
ProAndroidDev
Published in
5 min readNov 8, 2020

--

MotionLayout (a subclass of ConstraintLayout) is aimed at making user controlled animations very easy and maintainable. It was first introduced in Google I/O ’18 and since then it has been going through many improvements. An awesome editor (a.k.a MotionEditor) support was added in Android Studio. I have been playing with its powerful API to build components with animations to common user events.

Most popular messaging, email apps feature a swipe behavior on individual message/email items to provide more contextual actions relevant to that item. For example, this is how Gmail app email swipe looks like; swipe left to archive message, and swipe right to delete message.

Email Swipe behavior in Gmail app

In this article, I explain implementing a SlideView component (ex: sliding an email in popular email apps like Gmail, outlook, yahoo etc.. or messages in Messages app) using MotionLayout instead of other traditional ways. To illustrate the MotionLayout and its animation features, I used a simple view element (like TextView) on which swipe actions can be performed. But this view can be easily replaced by a complex Custom View with the same rest of the behaviors/animations. Once finished, the example looks like this.

Swipe View built using MotionLayout

Let’s begin. First, we need to get the MotionLayout and its relevant library classes in our dependencies. MotionLayout is being released inside Constraintlayout.2.0

Add this to app/build.gradle and do grade sync, we are good to go.

MotionLayout (similar to ConstraintLayout) lays out its children elements using their constraints (w.r.t parent or sibling views). However, since MotionLayout specifically enables us to animate views more seamlessly via its powerful API, it requires us to split the UI representation and User events/view animations in two different files. Let’s go into more details.

  1. It needs a layout file that specifies all the views in the view hierarchy. Let’s call it motion_layout.xml
  2. It needs a separate file to explain the motion scene, where we describe the start and end states of transitions with the user behavior attached (if any). Let’s call it motion_scene.xml

Both of these files are linked together via the layoutDescription tag in the MotionLayout node.

Building the MotionLayoutSwipeView:

In our case, we want to build a view that has the ability to slide left and right based on user’s swipe action while revealing or hiding certain other views as needed. For example, in a typical email app, when user swipes the view towards left, we would like to show a “Forward” and “Archive” actions. When the user swipes to the right, we would like to show a “delete” action with some animation attached to it providing visual cues that the email is deleted.

Step 1:

The first step is to build the MotionLayout’s layout file, with all the relevant UI views appearing in the rest/start state. For the sake of simplicity, I’d like to use a TextView as the view to be swiped, but this can be easily replaced with any Custom View.

So the motionLayout root has all the children views, a TextView to show some text that the user can swipe on. A Delete ImageView for delete action, Forward and archive ImageViews for forward/archive actions respectively.

Now the motion_layout.xml will look like this:

Step 2:

The next step is to define the content of motion_scene.xml (with a MotionScene root node). Here we need to specify all the various states that our views go through and their corresponding transitions and animations. A State contains all the information pertaining to how the views are aligned in that particular state. State details are specified via ConstraintSet tag/class. The Transition tag describes the MotionLayout system a journey between two states, the duration for that journey and other user actions (if any).

In our use case, we have one swipe left action that changes the UI from two states i.e from rest/start state to a state where forward/archive image views are shown, let’s call this end state as “end1”. We also have another swipe right action, that changes the UI from rest/start state to a state where we show delete image view, let’s call this end state as “end2”. So we have a total of 3 states, and 2 user behaviors (a.k.a transitions). Let’s name the transitions leftSwipe and rightSwipe.

Our 3 states (start, end1, end2) are specified along with the view alignment as below:

The transition details are specified via the Transition tag with a name for the transitions, start and end states. The example below shows the transition from “start” to “end” states in motion_scene.xml:

With this, we should have basic user interaction of the swipe views and corresponding views being shown accordingly as needed. As you might have noticed, we have not touched anything inside the Activity for any of this behavior! This is where MotionLayout shines bright (compared to various other Layouts) and where complex motion animations can be achieved without writing a single line of code! The layout, its states, animations and transitions are self-contained in XML files.

We are not finished yet.

For a typical delete action, the message/email should be removed from the UI screen, and behind the scenes a database/network call needs to be made to update the record accordingly. Focusing on the UI aspect of this, to build a delightful visual experience, we need to show the user some animation when the delete action is selected. For example, we can fade out the delete icon at the end of the swipe right user action for example. MotionLayout makes it very easy to achieve this, and we shall see how.

MotionLayout provides an API to listen to various transitions it plays on its children view, and we can add our own custom transition listener via addTransitionListener method of MotionLayout class. This is done inside Activity class that is inflating the motion_layout.xml

There are a few methods that we can use to listen for transition updates (when a transition started, completed, triggered etc..) and in our case we’d like to listen to the transition completed (onTransitionCompleted) which we use to fade out the entire motion layout view component (including all children views) The code below shows how this can be done:

As you can see, at the end of a transition, onTransitionComplete() callback is invoked by the Android system, in which we can perform post transition operations. In our case, we plan to run another animation to slowly fade away the delete image view (for a duration of 250ms) and show a toast message saying “Message deleted!” at the end of that animation. The above code shows exactly this.

In summary, MotionLayout helps us build complex view motions based on user interactions, while automatically reversing that motion, all out of the box!

I hope you found this article helpful! Please leave any questions/comments below. Also I would love to hear how MotionLayout is helping your app screens become lively!

Thanks for reading!

--

--

Lead (Staff) Android Engineer @intuit. I write mostly about Android development, framework APIs, advancements etc. follow me @balarka on twitter.