React Native Reanimated 2 : Implementing a simple snap to corner gesture animation

Alaa Chakroun
eDonec
Published in
5 min readFeb 14, 2021

Smooth 60 frames per second animations even on low end devices.

Photo by NordWood Themes on Unsplash

Implementing gestures and animations in our mobile applications is often required to provide a delightful user experience in the final product.

React Native provides us with its built it Animated API but more often than not, the performance leaves too much to be desired especially in low end Android devices and that’s caused mainly by one culprit; the bridge.

To keep things simple, let’s say that on every frame of the animation, information has to be shared between the JavaScript thread and the UI thread and, in the best case scenario, this takes about 1 frame (or 16ms at 60 fps). Add to that all the app logic running on the JavaScript thread (fetching data, looping arrays, mutating objects…) and those delays become more and more apparent resulting in sluggish animations.

Reanimated 2 :

Thankfully, the react-native-reanimated library exists to tackle this very problem, by allowing us to run animation natively on the UI thread and thus eliminating any kind of delays.

The second version of this package, or what came to be known as reanimated 2 in the community, provides us with a set of useful hooks and functions allowing us to write cleaner code, less boilerplate and using plain JavaScript instead of the library’s own functions compared to the first version.

We need to keep in mind that reanimated 2 is not officially released yet and still in a release candidate stage as of writing this article.

The rest of this article will be dedicated to implementing a snap to corner gesture animation (Similar to the picture in picture window in iOS 14) using reanimated 2 in React Native.

The Animation :

First we created our blank React Native project, and replaced our App.tsx file with the content below :

Next we can run our application in the simulator by running yarn ios in the command line in this is the output :

We can see our container filling the whole screen, and our red circle of 100pt width that we are going to animate.

The Drag :

Next up, we are going to install the react-native-reanimated package for our animations as well as the react-native-gesture-handler package to respond to user gestures.

Setting up reanimated 2 is a bit more than just running a yarn add react-native-reanimated so taking a look to the Documentation might come in handy.

Next we can rerun our application and, if everything has been set up correctly, we should see our screen unchanged.

In order to handle the user gesture, we need to wrap our circle to animate with a PanGestureHandler from react-native-gesutre-handler and, using the useAnimatedGestureHandler hook from react native reanimated, we can start setting up our gesture handler.

In order to enable the dragging on our Animated.View, we are going to animate the translateX and translateY of our View depending on the translationX and translationY of the PanGestureHandler.

Few things to notice here :

  • We moved our styles.circle from the StyleSheet.create function to the useAnimatedStyle from react-native-reanimated in order to enable us to use animated values in the style.
  • We used the useSharedValue hook to create our Animated values in order to make our animated values accessible from both the UI thread and the JavaScript thread.

We can check our animation when running in the simulator and, while the dragging works flawlessly the first time, trying to drag for a second time doesn’t work quite right.

This happens because the translationX an translationY values reset to 0 when the user initiates another pan gesture, so we have to, for each gesture, remember the last drag coordinates, and use them as an offset for the position calculation in the next one.

Fortunately, the useAnimatedGestureHandler hook gives us exactly the tool we need; for every handler we can use the context object passed as the second argument to store information between the handlers.

And now our dragging works correctly and we can finally tackle the snapping to the screen corner.

The Snap :

This final part is composed mainly of 3 steps :

  • Specifying the snap points for our X and Y axis.
  • Calculating the correct snap point.
  • Animating our animation values to the correct snap point.

In our case, in the X axis we need to snap either to 0 (right most edge of the screen) or to the screen width minus the circle diameter, while for the Y axis we snap to either 0 (top of the screen) or to screen height minus the circle diameter.

Once we declared our snap points, we can either write our own method to handle the calculations of the correct snap point, or use William Candillon’s amazing work with the react-native-redash library which is a set of various helpers related to everything reanimated (redash is basically a reanimated lodash). The method we’re interested in in our example is the snapPoint method that takes as an argument the value of the gesture, its velocity and the snap points array.

Finally, we can finish things off by using a spring animation to provide a physics based spring animation to our animation value.

So here is our final code :

And here is our final animation running in the simulator :

Conclusion :

The React Native Reanimated 2 library is by far the gold standard of animation libraries available in react native as it offers great performance compared to other solutions, and requires less boilerplate code in order to set up a great user experience. In this article we didn’t even scratch the surface of what’s possible to achieve using these tools and I’m excited to see more of what can be done.

--

--