Animations rarely change the core functionally of an app but you can’t deny that they make a big difference for the user. When an app has great animations everything looks more fluid, it’s easier to understand how things fit together.
Transitions are used when you’re moving from one screen to another and you want to apply animations to one or multiple elements. In this article I’ll show you how to implement them in your app.
We’ll start with an app that has no animations and add the needed ones to improve it.
Before we start, make sure you’re not using the wrong library version.
If you’re using
androidx.appcompat:appcompat:1.3.0 you’ll have to manually specify
appcompat:1.3.0 depends on
fragment:1.3.4 that introduced a bug related to fragment transitions.
I was getting an
IndexOutOfBoundsException exception when messing around with shared transitions and I took me a while to discover that the fragment library was the problem.
java.lang.IndexOutOfBoundsException: Index: 5, Size: 5 at java.util.ArrayList.get(ArrayList.java:437) at androidx.fragment.app.FragmentTransitionImpl.setNameOverridesReordered(FragmentTransitionImpl.java:183) at androidx.fragment.app.DefaultSpecialEffectsController.startTransitions(DefaultSpecialEffectsController.java:665)
Now let’s get started
If no return transition is set, the transition system will automatically reverse the enter transition when navigating back.
By default, transitions run on all child views within their scene root hierarchy. For example, if you have a RecyclerView, the animation will be applied to it and to its children. If that’s not the behavior you expect, set
android:transitionGroup="true" on the view group to disable that. You can also apply it to the out most view in your layout to make the fragment animate as a whole.
If you have views that are populated after the fragment is created (a RecyclerView for example) you need to tell the transition system to wait before starting the transitions. To do that you need to call
postponeEnterTransition to postpone the transitions and call
startPostponedEnterTransition when you’ve populated your views.
We’ll start with one of the simplest transitions, MaterialFadeThrough. The fade through pattern is used for transitions between UI elements that do not have a strong relationship to each other.
The transition here consists of going from the items fragment to the cart fragment. On the first fragment we define
On the destination fragment we define the same transition but on
If you’re using a RecyclerView you might need to postpone the enter transition on the destination fragment. To learn how to do that, take a look at the Basic Knowledge section.
This transition is a good option for navigating between fragments when you have a bottom navigation bar. The fade is subtle but adds a nice touch to the navigation.
In a fade through transition, outgoing elements first fade out. Next, incoming elements fade in while scaling in overall size from 92% to 100%. The element scaling starts at 92%, rather than 0%, to avoid drawing excessive attention to the transition. The scale animation is applied only to incoming elements in order to emphasize new content over the old.
The fade transition is usually used with dialogs, menus, or things that fit within the bounds of the existing screen.
MaterialFade transition is basically the same as implementing the
MaterialFadeThrough transition, the only difference is the transition name.
When entering, elements use a fade and scale in overall size from 80% to 100%. The scale animation starts at 80%, rather than 0%, to avoid drawing excessive attention to the transition. When exiting, elements simply fade out. The scale animation is only applied to entering elements. This places emphasis on new content (entering elements) over old content (exiting elements).
They look very similar but by looking at the specification we can see one main difference.
Fade – Scales from 80% to 100%
FadeThrough – Scales from 92% to 100%
MaterialSharedAxis transition is well suited for cases when you want to represent some kind of spatial relationship. Opening a search page would be good example, when the user searches something, the content below is expected to change.
For this transition to look good you need a pair of fragments to animate simultaneously. Their transitions will run together to create a directional animation.
You can control the transition direction by specifying the
forward property on
MaterialSharedAxis. In the forward direction, targets of the transition will scale out.
On this example we’re using the Z axis but you should give the X and Y axis a try to see what they look like.
For the transition to look great you need to specify the same
forward value for
This is the transition I love the most,
MaterialContainerTransform is used as a shared element transition, that means it’s used to transition the view’s size, position, etc from the start state to the end state.
The Container Transformation is used a lot when you have a RecyclerView that’s already displaying some portion of the content that’ll be available at another screen. By using this transition you can animate the change from one place to another.
First we need to specify a
transitionName on the view we wish to transition. Transition names have to be unique, that’s why I’m adding
layoutPosition to the end of the transition name. If you’re using a RecyclerView, you should do this when binding your ViewHolder.
Now on the end layout file, add a
transitionName to the view the animation will end on.
We want the transition to start when the item is clicked, on the item clicked handler we have to tell the transition system the views from the start state that will map to the end state. For example the
icon that was clicked on the RecyclerView will transition to the view on the end layout that has
transitionName you specified on the ViewHolder is just used by android to keep track of things, you won’t use it anywhere else.
Finally we specify the
MaterialContainerTransform on the destination fragment.
drawingViewId is the view that’ll be used as a plane for the animation, if you’re using Navigation specify your NavController view.
If you want your animation to follow an arced path, you also need to specify the path motion.
There are many ways to customize your transitions, you can learn more about them here.
As I’ve said before, if you don’t specify a return transition, Android will automatically use the enter transition reversed.
Take a look at the last GIF again, the
MaterialContainerTransform looks good but everything else uses a rough transition. Let’s learn how we can use many transitions together to achieve a better end result.
In some cases you might need some help to understand what’s happening behind the transition and there’s a simple thing that can help you with that.
MaterialContainerTransform has a
isDrawDebugEnabled property that adds visual information to the transition.
We’ve learn learned about the 4 transitions provided by Material individually, now let me show you how I used 3 of them together to create an animation that is pleasing to the eyes.
First I started by using the
MaterialSharedAxis transition on the list fragment, it works well because the views reduce size from 100% to 92%, that helps to focus on the icon animation.
Then I added the
MaterialFadeThrough transition to the destination fragment but I excluded the icon from that animation because it’s already being animated by
By doing just that the end result is much better
If you have any doubts you can find the source code here or contact me.
The best way to learn is by doing, go and apply the knowledge you’ve acquired here to a concrete example. I’d enjoy seeing what you can accomplish. I hope this article was helpful for you.