Implementing Complex Animations in Android (Full Working Code)

Muhammad Wajeeh
Jun 2, 2017 · 5 min read

Android has excellent support for animations but sometimes you see something like this:

Salon categories by @fozail29 | Source

and get stuck and wonder where to begin. In this post I will try to accomplish this beautiful animation and go through each step.

There is lot going on when you see it at first but we can break it down to three major animations.

1. The animation that plays when user taps on the card:

2. The animation of launching another screen with details:

3. Scroll up animation which shrinks icons to dot indicators:

I will try to implement 2nd and 3rd, 1st one is easy and is left as an exercise for developers.

Remember Shared Element Transitions were added in Android 5.0 (API level 21)? You just tell the OS about the views that are shared between current and next screen (Activity or Fragment) and OS will take care of doing a smooth transition of those views from old state to new state which can involve translation, rotation, scale and visibility etc. It can even do matrics animation on ImageView.

We will utilize Shared Element Transitions in our first animation. We have a RecyclerView that shows circular images. On tap of any of those, we want to animate all the visible items to correct place on the next screen. For that we will have to ask LayoutManager for visible item positions:

Once we have visible positions, just get the itemView associated with positions and start the next activity with those views as shared elements:

On the next activity, all you need to do is assign that unique_key_x to some views and OS will take care of this animation. We are using IconPageIndicator which shows corresponding icons as indicators for ViewPager so we set same transition name for same position in IconPageIndicator

view.setTransitionName(“unique_key_” + i);

and voila! we are already done with first part of animation.

Second part of animation that we are trying is fairly complex. There is lot going on when you scroll the list. Icons shrink to dots as you scroll up and when you scroll down, dots expand to icons. Another interesting thing is that this indicator stays centered vertically at all times in Toolbar.

First thing first, we want our IconPageIndicator to stay centered vertically when our Toolbar expands or collapse (of course we are using CollapsingToolbarLayout with CoordinatorLayout). CoordinatorLayout, as documentation puts it, is a super powered FrameLayout. Each child in CoordinatorLayout can listen for interesting events happening to other childs via CoordinatorLayout.Behavior and can respond accordingly. We will use that to our advantage to stay centered vertically inside CollapsingToolbarLayout:

First we let our Behavior know that we are interested in AppBarLayout:

and then whenever onDependentViewChanged() is called, we do our magic while respecting android:fitsSystemWindows="true":

This will keep the indicators centered. Now we have to shrink icons to dots when user scrolls BUT if you were paying attention, there is another thing going on here; Dots are centered horizontally but icon indicators start from middle and scroll horizontally when you scroll ViewPager. That means we need to center indicators when shrinking to dot.

Let’s divide and conquer here. We will add the start and end padding in indicators so that it starts showing from middle. We do this in OnPreDrawListener because we can only do it once views are measured:

Now, let’s move onto shrinking part. Remember we overrode onDependentViewChanged()method in our Behavior. This method will get called everytime there is a change in CollapsingToolbarLayout. We can get total scroll range and current scroll, which are the only two things required to tie our animation with scroll:

child.collapse(-appBar.getTop(), appBar.getTotalScrollRange());

and inside collapse() we can do our trickery of scaling down the icons to dots. Be careful though not to shrink icons to oblivion, dividing by 1.2 worked fine for me:

We also want our icons to become gray indicators on scroll up so for that:

At this point our app has almost everything it needs to look like the one we saw in gif. Except there is still room for improvement! Notice that dots are just perfectly centered horizontally. We want to achieve that smoothly during up and down scroll. If we denote current collapse percent with p, center of indicators as c, current selected expanded icon position as s and scroll along x-axis as sx then we can write this relation down as an equation:

sx = (p x c) + ((1 - p) x s

Which basically means that when p changes from 0 to 1, we change the scroll in a way that it either gives full weight to center position c or current selected position s, at peak values. In code it looks even uglier:

And when you hit run you see this!

Next Read:

Resources

Full source code:

Motivation behind this post: https://stackoverflow.com/q/43542302/826606

If you have a better way to implement this animation, shoot it out in the comments or create a pull request. Feel free to ask any question and suggest topics which you think I should write on in the future.