In the last episode, Dan said in the comments: "if
I'm not asking for much I would love to see an example of a shared element transition".
Well Dan, no you're not. Let's do this! :) So in this video we're going to work on
a great transition between two screens using React Navigation and React Native Shared
Elements. First, let me tell you how it's going to work. At the moment, we have two pages: one showing
a list of items to sell and another one to show an item details. So once we tap one of those items,
we get a modal showing up with all its information. Now, the transition we'd like to add is for the
image. As you can see, we already have a small one for every item in the list but also, and this
time in a larger size, in the details. The idea is, instead of having the same image on two different
screens, we'd like to smoothly transition that same image from the list, to the slightly bigger one
on the details page. For now, let me show you our two pages without the transition just so you get a
gist of what we're working with. So our application is using a simple stack navigator, where each
screen goes on top of each other, and we have the list i mentioned earlier, ListScreen, and another
one, DetailScreen, that shows an item details. If you're unfamiliar with React Navigation, all
we're doing here is defining different routes, the different screens: the list and the details here. So
the idea is that when we press an item, we should navigate from List to Detail, passing details from
one screen to another just so that DetailScreen can show everything. If we look at ListScreen,
we have a header and a View that renders all the posts. By the way, every post you see here, comes
from a different file. Each one has an id, title, description, price and image. If we go back to the
list, you can see there is some additional logicĀ here just so we get some spacing between every
two posts and also so that each item takes half the size of our screen. To render all the posts, I'm
now using a FlatList just so it's simple to read but obviously, if you were to play with really big
lists of items, you should use a virtualized list instead. Alright, now if we look at the Pressable
component around every post we have, when the post is pressed, we are redirecting the user to the
Detail screen, passing all the post information. Then, if we move to the other screen, we can
retrieve this information using the route parameters which should now have a "post" value since that's
how we named it when passing it from the list. We can then use this information to show
the image and everything else nicely. If you're curious about the styling, you can
find a link to the code in the description but we'll be focusing our attention on the Shared
Elements today. Speaking of which, now that you have seen the two pages, we can start adding the
shared transition I've been talking about. Let me just explain quickly how the library works.
Basically, shared elements needs to know which element should be shared between two different
screens. In our case, we just want to animate an image but it could be the title as well or any
other element really. To let the library know that we're sharing an image, we need to wrap
each element with a SharedElement component. All it takes is an id property, that should be
identical on both screens so that the element can be tracked. So here, we'll import the SharedElement
component and wrap our two images with the same id. Because there is not just one image but mainly
in our list, we'll pass a unique id for each image. So the first one will be "a" since that's the first
post id, and when we navigate to the details with the same post information, that our image can get
that id for the Shared Elements library to grow the image size. Now that we've specified which
elements should be shared, we need to let React Navigation know when to trigger the transition. Of
course you might think, "it has to happen when we navigate to the detail screen" and that's correct
but right now, the Shared Elements library isn't connected to React Navigation. So we need to link
these two, for Shared Elements to start animating the elements when switching screens. That's why we
needed the React Navigation wrapper actually, so it already knows how to do all this. Our first step
will be to change our stack navigator to a Shared Elements stack navigator. It's the exact same thing
underneath but with sharing elements capabilities. We're still missing something and that is to say
which screen should trigger the animations. Again, in our example, we should animate the image when
we go from List to Detail. So we need to let the navigator know that when we're switching to
Detail, a shared element transition should begin. For this, all you need is to add a sharedElements
property to the destination screen in Detail. It takes a callback that should return
a list of shared elements ids to animate. So if we had two elements with the id "shared" and
would like to animate these, we'd return a list with "shared" in it. But for us, we need to animate
our image which has a post id for its shared id. Since we can get that information from the route
parameters, just like we did in the Detail screen, the callback takes a route parameter which we can
use to get this id. Perfect! Now we have everything to admire our smooth image transition, let's have
a look. So, it looks good and we could stop there but I think the transition could be a little nicer.
You might have seen the icons flickering a little. This is because the way Shared Elements works is
by adding a layer on top of your application that animates the element from one position to the
other and then disappear once the transition is over. So you get the impression of an element
morphing from one shape to another. The thing is that while this is happening, our modal here is
also transitioning below this magic transition. And so our icons are moving behind the transition
and can only be seen after the transition layer from Shared Elements has been cleared. What we
can do is to hide the icons and fade them in after the transition is done. So that it looks
much smoother when we're on the DetailScreen. It is actually quite simple to implement: we'll
turn the View around the icons into an Animated one and animate the opacity from 0 to 1 just
so we get this fading effect. We'll import Animated, create an Animated.Value for the opacity and
make it start at 0. Also, remember to attach it to the View by first turning it into an Animated.View
and second, by adding the opacity to its style. After the screen has mounted, we can start
the fading animation that will take the opacity value to 1. And because we want to
start the fading not straight away but after the image has been transitioned, we need to
add a tiny delay, let's say 500ms. Alright, pretty, pretty cool! Actually we can
even make this animation better and I'll show you just so you can also start thinking about
different ways of improving it. Let's not just animate the icons but also the text, so that we
focus on the image and the title first, and only then we see the description. To do so, let's turn
the description Text component into an Animated one as well, and add the same opacity styling to it
so that it animates at the same time as the icons. Pretty simple, isn't it? Alright, let me recap
briefly what we've done here. We started with two screens: a list of posts and another one for
post details. Both had an image, so the idea was to transition the same image from one screen to
the other. For that, we used React Navigation for app routing and a wrapper around React Native
Shared Elements that works well together. The first step was to wrap both our images in a
SharedElement component, that lets the library know which elements are shared. For this, an additional id
was necessary to really identify this connection. After this first step, we turned our stack navigator
into a Shared Element stack navigator which gets shared elements capabilities. The idea is to
make the navigator start a shared transition automatically once we navigate from one screen to
another. To let the navigator know when and which elements should be shared, we added a "sharedElements"
property on the destination screen that should trigger a smooth transition. And
because that transition should happen with our Detail screen, we added the callback to this one,
that gets the post information from the route parameters and therefore, could retrieve the post
id we use to identify our images. This function must return the list of the shared elements that
should be animated. Finally, because our icons were flickering, we animated their opacity, following
the post description which all were animated using a timed animation that runs half a
second after the screen has mounted. Okay, I truly hope you found this helpful, and if you
did, there's a lot more to come on this channel. Remember to subscribe if you don't want to miss it, Thanks for watching and see you next time :)