Why are animations important?

Animations are important in order to create an optimal user experience, especially in the mobile world. App users have been exposed to a lot of them already, and have become familiar with their usability and beauty. And since they have hands-on experience with them, they expect them as a given in every single app they download. As per the React Native animations documentation:

Objects in motion have momentum. Animations allow you to convey physically believable motion in your interface.

Image 1: Animations are awesome!

Animation systems in React Native

React Native provides two complementary animation systems: Animated and LayoutAnimation. These are 2 different APIs with a different usability and purpose.

My personal feeling is that Animated is more widely used from developers, probably because it provides more control — and it also comes with better documentation.

In this article I assume that you are familiar with Animated API and I will blog on how to achieve the best performance out of it, alongside some other practical tips.

Animated API tips: Performance and more

In order to create an animation you can find very good documentation and “how to start” examples in React Native animations documentation.

How to achieve great performance

To achieve great performance you always need to make use of the configuration prop useNativeDriver (with value set to true ). For example, in order to animate the rotation of an image our timing function would look like that:

Animated.timing(

this.state.spinValue,

{

toValue: 1,

duration: 3000,

easing: Easing.linear,

useNativeDriver: true

}

).start();

This config prop is very very important because that way, RN sends the animation to be executed at the native realm directly passing through the bridge only once, thus achieving the best possible performance. If you are not familiar with the JavaScript/native realms and their bridge, you can get more insights in this post by @TalKol.

Now, according to RN documentation useNativeDriver prop cannot be used for all animation types:

Not everything you can do with Animated is currently supported in Native Animated. The main limitation is that you can only animate non-layout properties, things like transform and opacity will work but flexbox and position properties won’t.

There is a way though to overcome this, if you are composing animations. For instance let’s take an example from the Math Warriors Android app where we change the size of our logo image when the user clicks the start game button.

Image 2: Logo size increase animation when start game button is clicked in Math Warriors

What we do at this point is that we change the width and height of the logo simultaneously and these properties do not support use of the animated driver property. Their parallel execution though does support it as shown below:

Animated.parallel(

[

Animated.timing(

this.state.rankImageWidth,

{

toValue: 110

}

),

Animated.timing(

this.state.rankImageHeight,

{

toValue: 110

}

)

],

{

useNativeDriver: true

}

).start();

How to perform animations in loops

RN does not support loop animations out of the box, so we had to find a way. A 2nd example from Math Warriors game, which is actually the extension of our previous example, is the following: as soon as the user presses the start game button, the logo increases its size and also starts moving up and down in a loop and until the app matches the player with an opponent.

Image 3: Logo movement animation in a loop when start game is clicked in Math Warriors

We performed this by creating a JavaScript interval id. The catch here is that in order to avoid app glitches and waiting time, you need to execute the actual animation twice: the 1st one and all the others that will follow inside a loop (JavaScript interval).

// Animation function that moves an element over y axis over time

const upAndDown = (yPositionPropName, duration, yHighPosition, yLowPosition) => {

Animated.sequence([

Animated.timing(yPositionPropName, {

duration: duration || 1000,

toValue: yHighPosition

}),

Animated.timing(yPositionPropName, {

duration: duration || 1000,

toValue: yLowPosition

})

]).start();

};

// Call and use the function above

// Start up & down animation for the first time before the loop takes over

upAndDown(

this.state.rankImageTopPosition,

this.rankImageMoveDuration,

this.rankImageHighposition,

this.rankImageLowposition

); // Loop rank image up & down movement. Total interval time

// is (animation duration x 2) time for the whole up & down move

this.rankAnimationIntervalId = setInterval(() => {

upAndDown(

this.state.rankImageTopPosition,

this.rankImageMoveDuration,

this.rankImageHighposition,

this.rankImageLowposition

);

}, this.rankImageMoveDuration * 2); // Clear the interval id after we match our player with an opponent

clearInterval(this.rankAnimationIntervalId);

How to use animatable components with styled components

For the users of styled components you can convert any of the 4 animatable components ( View , Text , Image , ScrollView) to a styled component like that:

const AnimatedImage = styled(Animated.Image)`

.

.

.

`;

Validate animation’s real performance

In order to understand how your animation will behave you need to test it on a real device. Emulators cannot provide this kind of feedback. On the contrary, your animation may run flawlessly in an emulator environment and be sticky on a real device. Only the real device test can reveal if the animation shows at 60 FPS or less, which is when we experience slow breaking animations.

What do you think?

What do you think about these animations’ tips? How do you make your animations work for you? Offer your perspective and ideas in the comments section below.

Do you have a specific subject that you would like me to cover? If I have worked with it, I will be more than happy to share my perspective.