Creating Onboarding Flow with MotionLayout
The Android platform offers the ability to completely customise components that are not available in the prebuilt widgets and layouts or modify some existing components to meet our needs. However, making apps more accessible with complex UI requires some additional effort and sometimes nearly impossible. Fortunately, the Android team are continuously working to help us resolve some of these constraints by adding new classes and support libraries to the platform, such as ConstraintsLayout
Disclaimer: This article assumes that you’re familiar with
MotionLayout
and Circular Positioning withConstraintsLayout
. If not I recommend Introduction to MotionLayout (part I) by Nicolas Roard and ConstraintLayout: Circular Positioning by Andrew Kelly as a starting point.
Recently, I was assigned a task to create an onboarding flow with multiple screens for a client, to showcase a new feature in their Android app. Usually, I’d build such onboarding flow using a ViewPager and animates between these screens using transitions. But this time, I chose to build it with MotionLayout
after some reading and tutorials on MotionLayout
.
In this article, I’m going to take you through my journey of creating this onboarding flow with MotionLayout
.
The Onboarding Flow
The onboarding flow(see gif below) comprises of three screens with two control buttons and a progress dot indicator. Each screen incorporates details about that specific screen, encased in a bubble background.
Navigating to the next or previous screen animates to the next or previous screen respectively along with the progress indicator getting updated. The details in the bubble are only visible when the bubble expands and obscure when shrinks.
Why using MotionLayout?
At a glance at the gif, using MotionLayout
may appear irrelevant to you, but allow me to elaborate. First of all, before MotionLayout
, I felt terrible at animations on Android, especially when dealing with custom views. I’d build it by creating a custom view along with the texts and images to a canvas.
Secondly, it is nearly impossible to get this right without callbacks in my animations implementation — probably, some more boilerplate code.
Finally, making these screens accessible isn’t going to be easy based on experience. I’d also need a custom AccessibilityDelegate
for my virtual views.
Fortunately, with MotionLayout
, I don’t need to worry about all these issues and allows me to focus on the main logic of the onboarding flow.
MotionLayout
is a subclass of ConstraintsLayout
and helps with widgets animations. Moreover, ConstraintsLayout
already supports circular positioning and works as the solution used in this article.
The Onboarding Layout
Earlier, I stated that the onboarding comprises of three screens. Which sounds like I’d also need three separate layouts, but with MotionLayout
, it is possible to use a single layout for these screens using constraint set for each screen. Cool, right?
Furthermore, since the bubbles have different details for styling based on design specifications, one way of tackling this is to add all the views in our layout and then position them independently. This approach can result in one large layout file, which is challenging to maintain.
However, I favoured creating a new layout class, i.e. OnboardingbubbleItem
that subclasses FrameLayout. OnboardingbubbleItem
inflates a view of the bubble, i.e. layout_bubble_item.xml. I strongly recommend this approach as customising is more straightforward with custom attributes and MotionLayout
now treats these views as its direct children.
Each OnboardingbubbleItem
is then circularly constrained from a centre point widget centerPointPlaceholder at a given distance and radius for both expand and obscure details states in the onboarding_motion_layout.xml and the constraint set transitions in onboarding_scene.xml
Animating the screens
By default, MotionLayout
uses MotionScene
, a separate file containing the animation specifications needed to transition from the start-position to the end-position of our screen.
But, since the onboarding contains more than two screens and I’d need more than two transitions for the onboarding flow to work. In other words, I’d need to transition from one state to the other. I choose to do this by code since handling these transitions in the MotionScene
file along with the progress indicator, and button state is very tricky in my opinion. However, if you have a better approach, please share in the comment section below.
As mentioned earlier, transitioning between the next and previous screen is accomplished programmatically in the OnboardingFragment
, the Fragment
that hosts the onboarding flow. Notices how the extension function navigate
is implemented. It updates the progress indicator and buttons states and sets the transition between the start and end constraint sets. Then animates to the ending position with motionLayout.transitionToEnd()
.
That’s all. Now you know how I built an onboarding flow with MotionLayout
. The full sample is available on Github, see the link below.
Lastly, I reached out to Nicolas Roard from the ConstraintsLayout
team at Google for help and tipped me on how to make this onboarding work with less code. So stay tuned for part two of this article. See you soon!
Thank you for reading. I’d love to hear your feedback, so please leave me a comment below.
Ernest is an Android professional, with experience in developing and maintaining high quality scalable Android applications. Ernest is currently working as a Senior Android consultant at DNB(MinBank) via Shortcut, previously EVRY (Digital banking services) and Zedge Inc. Ernest enjoys taking photos and playing soccer with his kids when he is not co-organising meetups for his local developer community.