React Native Folding Animation

Bogdan Sydorov
4 min readApr 21, 2020

--

WHO AM I

Hi! I’m a Fullstack Developer from Moneyveo. Currently, I work as a mobile developer using React Native. My specialization includes Python/NodeJS Backend development, Data Scraping, Database Management, Distributed Computing, et al.

FOLDING MOTION

Some time ago, my friend — Andrey Nikishaev, sent me one interesting layout animation which definitely intrigued me.

So I decided to create this one! I’m going to concentrate more on folding motion itself, rather than content layout.

TO ACTION

I’m going to use react-native-ui-lib — an array of complete components to ease composition and styling.

You can find all the source code in my repo.

Transforms

The core problem of this task is actually to simulate transform-origin on React Native. The latter doesn’t have this attribute or its analogs. Thus we have to implement it on our own. Luckily, I’ve found a wonderful article concerning peculiarities of rotation motion in React Native. It definitely deserves reading! The most significant information it contains concerns simulating transform-origin property using matrix calculus.

Core matrix calculations module.
Interface for using matrices in components.

These functions use component ref to apply native animations to it. You should use transform function, sending rotating component ref and rotation vectors to it. During the animation, we are going to continuously call this function with increasing value of y.

Panel

The Panel component encapsulates a single plane of flipping. Obviously, it has 2 sides: front — a side that one sees when a plane is not animated, back — a side that becomes visible when animation occurs.

First, we have to create an animated component. Inner AnimatedViews represent two sides of the Panel of rotation. These two components will be bounded to fronRef and backRef, we will use these refs in transform function.

There is a prop — animValue, it will be used as an interface to get a current state of Panel rotation. It varies from 0 to 1, where 0 is folded state and 1 is opened state. Also, we need 2 separate interpolated values each for a single side of Panel: frontValue represents rotation degree of the front side, backValue — of the back side.

For Panel to track changes in animValue we need to subscribe to it in componentDidMount method.

Also, don’t forget to set backfaceVisibility: “hidden”, otherwise, as some moments of animation you will see backface of the front side when opening.

Backface side visible.

List

This is a List component. Its role is simply to get items data and visualize a list of Item components.

tryAnimate — sort of a mutex to guarantee that only one item is animated.
stopAnimate — is called by an item when it’s finished animating to allow another item to be animated.

Pay attention to not use a FlatList here. In its core it asynchronously renders components, thus some bugs may occur. For example, when you open an item and scroll off so that this animating item gets clipped.

Item

We are going to use animations, particularly Animated and LayoutAnimation APIs. To work with LayoutAnimation we need to insert this part of code at the beginning of Item file:

Let’s define some constants:

We are going to organize open and close animations as sequences of animations of each Plane from which Item consists. So we need animation values to carry state of each Plane:

One of the problems that you will face it height change. There are two ways to do it. First — animate height directly using Animated.Value interface. The issue with this approach is that height animation doesn’t support native driver. So it will be laggy when animated. The better way is to use LayoutAnimation! In short, it allows animating layout change. This functionality is implemented in function animateHeight:

To control the next state of animation, we can create a state property — nextAnimation, and change it after each animation occurs as a callback.

Also wherever as possible use native driver for animations. This separates all work for animating components to the native UI thread. Thus we can block JS thread without interrupting animation.

Here we can see the full code of an Item component. animateForw() and animateBack() are those methods that perform a complete animation.

When Item is pressed, animate() method is called. It checks if the animation can occur(whether or not there is another animating Item) and calls the appropriate nextAnimation() method. After animation completes, it calls stopAnimate() prop to release the mutex.

Here how final animation looks like:

Conclusion

In this article, we created a nice folding animation on React Native. Also, we considered several peculiarities concerning rotation in RN, using native driver etc.

And again, you can find all the source code in my repo. Feel free to comment and/or criticize.

--

--