Wyko Rijnsburger     About     Feed

Lessons Learned from implementing a Fragment to Fragment Shared Element transition

Discover transition gif Recent issues transition gif

1. Fragments should be in the same container

You cannot do shared element transitions with fragments in another container.

2. Use .replace() instead of .add()

Shared element transitions do not work when adding fragments, even to the same container.

3. Enable reordering allowed when postponing transitions

When the content of the transition needs to be loaded before the transition can start, we need to use postponeEnterTransition(). Postponing the transition will only work when you add setReorderingAllowed(true) to your fragment transition (see Android docs and the Reordering part of this blog post by Chris Banes for more context.)

4. Properly resume the state of the fragment you return to with the return transition

In this case, the view that needs to be resumed contains a nested RecyclerView within the main RecyclerView. The shared element needs to be in view in both fragments when the transition takes place. Therefore the nested RecyclerView needs to be restored to it’s previous state before the transition is started. This is done automatically when we use .add() to add the view because that means the view will remain in memory. However, using .replace() means that the fragment to which we need to return has been destroyed and needs to be recreated through the fragment lifecycle.

Using the onSavedInstanceState() and onRestoreInstanceState() methods of the nested RecyclerView, the state needs to be manually restored. startPostponedEnterTransition should be called when the shared element on the restored fragment is fully rendered.

5. To transition a CardView with an image, add both the card and the image as shared elements

Doing the transition on just the CardView won’t dynamically scale the image during the transition. If you do the transition on just the image, the card already be at its final position at the start of the transition.

6. postponeEnterTransition() and startPostponedEnterTransition() also work for return transitions

The naming of these functions is really confusing but they work exactly the same for return transitions.

7. setCustomAnimations fade-in/out causes shared element flicker. Individual fade-in/out fixes this

Using setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out) to add the fragment fade-in/out animation causes a subtle flicker on the shared element whenever the shared element transition is finished. This is fixed by setting a separate fade-in/out transition on the individual fragments:

currentFragment.exitTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.fade)
newFragment.enterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.fade)

However, these transitions persist past this fragment transaction. If the exitTransition of the fragment is not reset, a fade will be shown when returning to this fragment from other fragments, even if no specific animation is specified. We can easily clear this by resetting the exitTransition when the shared element transition is finished.

fragment.sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move).addListener(object : TransitionListenerAdapter() {
    override fun onTransitionEnd(transition: Transition) {
        // The current fragment transition should only be applied for this transition and be removed afterwards
        currentFragment.exitTransition = null
    }
})