Introduction to react-native animation

Bright Larson Nanevie
7 min readJan 2, 2023

--

Animation can add a lot of visual appeal to a mobile app and make the user experience more enjoyable. In this series, we will explore how to use animation in a React Native app. We will look at four different types of animation: spin, ping, pulse, and bounce.

Getting Started

In this blog post, we’ll explore a simple React Native animation example. We’ll create a spinning animation using React Native’s Animated API. By the end of this tutorial, you’ll have a better understanding of how to create basic animations in your React Native apps.

Setting up the Environment

Before we dive into the code, make sure you have a basic React Native development environment set up on your machine. You can follow the official React Native Getting Started guide to set up your environment.

Now that you’re all set and done, Let’s jump straight into it. 😊

Spin animation

A spin animation rotates an element around its center. To create a spin animation in React Native, we can use the Animated and Easing components from the react-native library.

Here is an example of a spin animation that rotates an image 360 degrees over a period of 2 seconds:

import React, {useState, useEffect} from 'react';
import {View, Animated, Easing, StyleSheet} from 'react-native';

function SpinAnimation() {
const [spinValue, setSpinValue] = useState(new Animated.Value(0));

useEffect(() => {
Animated.timing(spinValue, {
toValue: 1,
duration: 2000,
easing: Easing.linear,
useNativeDriver: true,
}).start();
}, []);

const spin = spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});

return (
<View style={styles.container}>
<Animated.Image
style={{
transform: [{rotate: spin}],
...styles.image,
}}
source={{
uri: 'https://images.unsplash.com/photo-1594074456536-f7c281aa6bcc',
}}
/>
</View>
);
}

const styles = StyleSheet.create({
container: {
height: '100%',
backgroundColor: 'green',
alignItems: 'center',
justifyContent: 'center',
},
image: {
width: 200,
height: 200,
borderRadius: 100,
},
});

export default SpinAnimation;

After running the above code, the spin animation will run for 2 seconds and then come to a stop. If you want to see the animation run again(which I know you cannot resist), you have to refresh your project by hitting R in your terminal, and you’ll see the animation run again(still only for 2 seconds). Now, I realize this is not an ideal situation. Isn’t it better for the animation to keep running so you can enjoy it? or even better, have a Start and Stop button to control the animation. Well, all of that is very nice but to keep the code at a bare minimum so that we can go through what the code is doing, this is a perfect place for us to begin. With that said, let’s see what is happening behind the scenes.

Animated API

The Animated API is used to create animations in React Native. It allows you to animate any property that can be expressed with a number, such as opacity, position, and scale.

Initializing the Animation Value

const [spinValue, setSpinValue] = useState(new Animated.Value(0));

Here, we declare a state variable called spinValue and initialize it with an instance of Animated.Value set to 0. This spinValue will be used to control the animation where 0 represents the start of the animation and 1 will represent the end of the animation

Setting up the Animation Effect

useEffect(() => {
Animated.timing(spinValue, {
toValue: 1,
duration: 2000,
easing: Easing.linear,
useNativeDriver: true,
}).start();
}, []);

Inside the useEffect hook, we define the animation effect. We use the Animated.timing method to specify the animation behavior. It takes several properties:

  • spinValue: The value we want to animate.
  • toValue: The final value to which the animation should progress (in this case, 1).
  • duration: The duration of the animation in milliseconds (2000 milliseconds or 2 seconds).
  • easing: The easing function that determines the animation's timing curve (linear in this case). NB: There are several easing functions but we will get to that later.
  • useNativeDriver: Setting this to true indicates that we want to use the native animation driver for improved performance.

Finally, we call .start() to begin the animation.

The useEffect hook is used to start the animation when the component is mounted. It calls the Animated.timing method to animate the spinValue from 0 to 1 over a duration of 2000 milliseconds.

Interpolating Animation Values

const spin = spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});

In this section, we create an interpolate function that maps the spinValue from a range of [0, 1] to a range of ['0deg', '360deg']. Now why do we need interpolation in the first place? Let’s find out!

  1. Limited Input Range vs. Desired Output Range: In animations, you often have specific starting and ending points for a property you want to animate. For example, in the spinning animation, we want to rotate an image from 0 degrees to 360 degrees. However, the underlying animation value (spinValue) doesn't directly represent the desired output range. In short, spinValue goes from 0 to 1, but we want the image to rotate from 0 degrees to 360 degrees. Thus we use interpolation to map this range [0, 1] to another range [0deg, 360deg]. This means that as spinValue progresses from 0 to 1, the interpolation function calculates the corresponding rotation angle between 0 and 360deg, ensuring a gradual rotation.
  2. Smooth Transition: Interpolation helps in creating a smooth and continuous transition between values. Without interpolation, the animation might jump abruptly from one value to another, leading to a less visually appealing result.

This means that as spinValue goes from 0 to 1, it will rotate from 0 degrees to 360 degrees.

Rendering the Animated Component

return (
<View style={styles.container}>
<Animated.Image
style={{
transform: [{ rotate: spin }],
...styles.image,
}}
source={{
uri: 'https://images.unsplash.com/photo-1594074456536-f7c281aa6bcc',
}}
/>
</View>
);

Before we explain what is happening here, let’s answer a few questions.

  1. Why use Animated.Image instead of Image
  2. How does transform property work be default?

The use of Animated.Image in React Native, as opposed to a regular Image component, is related to the integration of animations with the Animated API for improved performance and smoother transitions. Here's why you should use Animated.Image and how the transform property behaves by default:

1. Performance and Optimization:

Animated.Image is part of the Animated module in React Native, which is specifically designed for creating performant and smooth animations. When you animate a regular Image component by updating its styles directly, it can result in poor performance because it may trigger a re-render for every frame of the animation.

In contrast, Animated.Image uses the native animation driver (when useNativeDriver is set to true). This means that the animation calculations are offloaded to the native layer of the app, resulting in better performance. Native animations can be optimized for smoother transitions and consume fewer resources compared to JavaScript-based animations.

2. transform Property Behavior by Default:

The transform property in React Native is used to apply 2D and 3D transformations to elements. When you apply a transformation to an element, it alters its visual presentation, such as its position, rotation, scale, and more.

In React Native, the transform property is used as a style property for components. It takes an array of transformation objects, where each object represents a single transformation. The transformation objects have a type property that specifies the type of transformation, such as rotate, scale, or translate, and a value property that specifies the value for that transformation.

<Image
style={{
transform: [{ rotate: '45deg' }]
}}
source={{ uri: 'https://example.com/image.jpg' }}
/>

You can also apply multiple transformations to an element by adding more objects to the array. For example, to rotate and scale an image, you would use the following code:

<Image
style={{
transform: [
{ rotate: '45deg' },
{ scale: 1.5 }
]
}}
source={{ uri: 'https://example.com/image.jpg' }}
/>

Enough swaying off, let’s get back on track.

In the return statement, we render an <Animated.Image> component. This is where the magic happens. We apply the animated transformation using the transform style property. We specify that we want to rotate the image by the spin value, which is derived from the spinValue interpolation. The ...styles.image spreads the image styling from the styles object.

The styles object

const styles = StyleSheet.create({
container: {
height: '100%',
backgroundColor: 'green',
alignItems: 'center',
justifyContent: 'center',
},
image: {
width: 200,
height: 200,
borderRadius: 100,
},
});

Finally, we define the styles for the container and image using StyleSheet.create(). The container is given a green background color and centered content. The image is given a fixed width and height with a circular shape.

Conclusion

Whew, That was a lot. In the next section we will look at how to loop the animation so it keeps running forever and also add a Start/Stop button to control it.

See you my friends…. 👋🏽

Recap

In this blog post, we learned how to use animation in a React Native app using the Animated and Easing components. We looked at creating a spin animation, the Animated API, setting up an animation funtion, interpolation and why we need to use all of these tools. Using these components and techniques, we can add a lot of visual appeal to our mobile apps and enhance the user experience.

--

--

Bright Larson Nanevie

Full stack developer, NodeJs (express), React, React-native, MongoDB