Updated: Oct 1
Mobile devices are an essential part of our day. They are fast, compact and easy to use. However their small size holds both an advantage and a disadvantage - it limits the amount of information available on the screen, making apps feel fragmented as users are constantly navigating between screens. In this blog post I’ll be showing you a technique that you can use to create a sense of continuity as a user navigates between screens. As an added bonus, if your app is written in react-native and you happen to be using wix/react-native-navigation then you can implement this technique in a few minutes.
This simple technique is called Shared Element Transition (which we’ll conveniently refer to as SET from now on) and it essentially revolves around the process of animating elements from one screen to another during screen transitions. By animating meaningful elements the user is already familiar with, we create continuity and reduce the sense of fragmentation.
A simple example where this technique is implemented is Android’s gallery app. When clicking on a thumbnail the image seamlessly expands into the full screen preview:
How does it actually work?
Before we get to implementation, let's understand how SET works under the hood.
The first thing we should understand is that even though this technique is called shared element transition - no views are actually shared between screens. Shared Element Transition is simply a glorified Animator. All it does is animate the difference between view properties like dimensions, color and position to create the illusion that a view is shared between screens.
Here’s what we need to do:
The first thing we need to do is find both views in the appearing and the disappearing screens. We’ll conveniently name them ‘from view’ and ‘to view’.
Now that we’ve located the views involved in the transition, we need to calculate the difference in their visual properties. For example size difference or the difference in their position on the screen. By animating these style properties we are creating the illusion of a shared view transition.
We’re almost done! All that’s left is to create the animators, start the animation and our shared element transition is ready!
Want to hear more about React Native and how we use it? Listen to our podcast episode "Breaking Down React Native":
First, we need to find the shared elements in both the entering screen and the exiting screen. This task turned out to be more challenging than we have initially anticipated, but thankfully my colleague Yogev Ben-David has found a helpful undocumented prop called nativeID which alows us to do just that. By setting a nativeID prop on each shared view in JSX, we can then find these views using RN’s `ReactFindViewUtil`.
Notice how finding the exitingView is instantaneous while finding the enteringView is asynchronous. That’s because the existing view is already rendered and laid out while the entering view has not been created yet.
2. Now that we found the native shared views, we can animate the difference between the view properties. To calculate that difference correctly, the view that’s appearing has to be measured and laid out.
3. Creating animators is pretty straightforward. All animators are created but only the animators responsible for animating properties where there’s actually a difference are executed.
Let’s examine XAnimatorCreator which is responsible for animating the x coordinate of the view. When an animator is created, the difference between the views’ X coordinates is calculated. An actual system animator is created which animates the delta.
And that’s all to it - once an animator starts, ‘to view’ is transformed to look like the disappearing ‘from view’ and then animated to its correct state, thus making it feel like the views are actually shared between screens.
Why did we reimplement SET
Android’s SET implementation only supports transitioning elements in Activity or Fragment transitions, while RNN screens are contained in ViewGroups. In order for us to use Android’s implementation, we had to use Fragments as containers for screens instead of ViewGroups.
Having previous not-so-positive experience with Fragments and keeping in mind SqaureEng’s iconic blog post advocating against Fragments, we really weren’t too thrilled to replace our current implementation.
Chris Banes, a lead Android UI engineer at Google, has published a wonderful post on some of the unexpected challenges he faced while trying to implement SET in a pure native app. Adding to the equation RN’s async rendering nature and complex implementation of some views,
It actually seems that using the system implementation is nearly impossible.
Leveraging the powerful nativeID prop, and since all of the heavy lifting is done in native, we were able to expose the SET feature through a very lean API.
1. Set a nativeID prop to the image in the source screen
2. Set a nativeID prop to the image in the destination screen
3. Declare the shared element animation when pushing the screen
That’s it! This really is all that’s to it. With a few lines of code you can achieve amazing animations to really take your UX up a notch.
RNN’s playground application contains a more elaborate example where multiple elements take part in the transition. You can read more in the docs.
Conclusion and Plans for the Future
Introduced five years ago in Android 5, SET is still not seeing widespread adoption even though the benefits are clear to see. We’re hoping that an easy to use API will change that.
Moreover, In a recent post Google has revealed their plans for the future of Shared Element Transition showcasing a powerful new Transition Editor to bridge the gap between designers and engineers. We’re positive this will increase adoption in native apps which in turn will affect user expectations and increase adoption in RN as well.
At Wix, we have big plans for SET. In addition to already supporting SET in push command, we plan on gradually supporting it in all other commands as well; pop, showModal, dismissModal and even changing bottom tabs.
We’re excited to see what amazing transitions you implement in your apps! Tag us on Twitter @ReactNativeNav and show us your creations.
This post was written by Guy Carmeli
You can follow him on Twitter
For more engineering updates and insights: