Shared Elements Transition in React Native

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
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 :)
Info
Channel: evening kid
Views: 6,257
Rating: 4.9783783 out of 5
Keywords: react native, reanimated 2, tutorial, facebook, marketplace, shared element, shared transition, react native shared element
Id: mqKAzs-O1eo
Channel Id: undefined
Length: 10min 14sec (614 seconds)
Published: Wed Mar 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.