Introduction to react-native animation
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 totrue
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!
- 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 asspinValue
progresses from 0 to 1, the interpolation function calculates the corresponding rotation angle between 0 and 360deg, ensuring a gradual rotation. - 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.
- Why use
Animated.Image
instead ofImage
- 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.