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:
- Calculate selected recycler card end position (its position on
DerailsFragment
); - Save card current position and pass it to
DetailsFragment
as arguments (if we want revers transition on API < 21); - Create a copy of selected recycle card (lets name it new card);
- Make selected recycler card invisible;
- Add new card (from step 3) to the root layout of
RecyclerFragment
; - Animate all other views and translate new card;
- Create fragment transaction and show
DetailsFragment
when animation ends; - 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 ! 😅
Examples
You can get my CodingQuiz app from Google Play with similar UI motions:
or check out source code on github:
Thank you for reading and Happy Coding!
Don’t forget 👏