From Dribbble template to android motion

There are a lot of beautiful mobile animated UI templates on Dribbble and a lot of Android tutorials on Medium. But not a lot of how to implement UI motion templates in mobile development. I found a very good article written by @Jiří Otáhal about Animated Transition in React Native, where there is a good explanation about creating beautiful motions from one of Dribbble shot. But it’s about React Native. I think it’ll be interesting to implement these motions on native Android. Let’s try it together!

In this article we’ll also try to implement transition motions like on UI template created by Ivan Parfenov.

Great shot with a lot of motions! Let’s implement them step by step.

At first, we have two fragments in our app: RecyclerFragment and DetailsFragment.

The most difficult behind:)

May be Transition framework?

Android Transition framework works great but we need something other behavior. We need to start transition animation for selected recycler item, translation for toolbar, alpha and scale for recycler in RecyclerFragment at the same time. And we want to get it working at least on API 19. The most simplest solution is to using ViewPropertyAnimator and android transition tricks.

All by steps

It’s pretty simple:

  1. Calculate selected recycler card end position (its position on DerailsFragment);
  2. Save card current position and pass it to DetailsFragment as arguments (if we want revers transition on API < 21);
  3. Create a copy of selected recycle card (lets name it new card);
  4. Make selected recycler card invisible;
  5. Add new card (from step 3) to the root layout of RecyclerFragment;
  6. Animate all other views and translate new card;
  7. Create fragment transaction and show DetailsFragment when animation ends;
  8. Animate DetailsFragment views.

Views animation

For toolbar animation we’ll create a helper view above toolbar in RecyclerFragment layout file and set its initial translation by Y out of the screen. This view will be animated into DetailsFragment toolbar container (blue color on above screenshot) with ViewPropertyAnimator.

<View
android:id="@+id/details_toolbar_helper"
android:layout_width="wrap_content"
android:layout_height="@dimen/details_toolbar_container_height"
android:background="@color/colorPrimary"
app:layout_constraintTop_toTopOf="parent"/>
// In RecyclerFragment
details_toolbar_helper.translationY = -details_toolbar_helper.height

BottomNavigationView and RecyclerView are animated with ViewPropertyAnimator in the same way but without helper views, it’s very simple (just scale, fade and translate).

Transition trick

In simple words, android transition framework when starts a shared element transition just creates copy of transition views content (like print screen) and put them into ImageViews, then adds these ImageViews at the same positions into the root overlay layer of target fragment (or activity) and starts translate animations.

For us it’s not a case, because when android transition framework starts transition it destroys all other views and we can not animate them. But we want simultaneously animations: animate recycler, toolbar, navigation bar and card transition at the same time.

We can do our animations by adding selected recycler item’s view into the RecyclerFragment root view overlay layer and then translate it. But as per ViewGroupOverlay add(view: View) method documentation:

If the view has a parent, the view will be removed from that parent before being added to the overlay.

But for RecyclerView it’s not working. Selected view will not be removed from recycler after adding it into overlay.

To achieve the expected result we just copy content (like print screen) from the selected recycler item, add put that print screen into ImageView and setup its layout parameters and position.

Why we can’t just translate a selected view without creating a copy?

Because the recycler will also be animated and all its views become invisible and we can’t see the selected item transition animation.

After that we can add a new copied view into the RecyclerFragment root view and translate it to the target position.

And this is what we have now:

Not bad!

We’re in the homestretch

The last step is to begin fragment transaction as animator end action:

.withEndAction {
fragmentTransaction?.commitAllowingStateLoss()
}

Why do we use commitAllowingStateLoss?

Because if there is an orientation change during the animation, we’ll get an IllegalStateExсeption. This is a good article about this.

All that’s left to do is run the view animation in DetailsFragment. It’s very easy to do with ViewPropertyAnimator in way like in RecyclerFragment.

For the returning transition we at first animate all views and then the android transition framework transit our shared elements.

And let’s play all animations together:

Not exactly the same as on the UI template created by Ivan Parfenov, but I think looks nice.

And what is about API?

The shared element transition works only on API ≥ 21. But our enter transition works without android transition framework (looks good on API 19), we only use the transition framework for return transition. And we can implement the return transition by hand in the same way but in a reverse direction. We can pass the old recycler item’s coordinates as arguments in DetailsFragment and at that time we can animate details card to that old position (aka returnSharedElementTransiton) and animate all view while transition happens.

That’s all ! 😅