React Native Animation is an interesting topic where a dull application could be converted into an interactive and beautiful app. Working with animations could look a bit overwhelming at first but it is essentially a process of just 3 steps.
Introduction
In this guide you will learn about the basic principles of React Native animation. I have divided it into two sections –
- Go through section 1 if you want to quickly run your animations with minimal information.
- if you want to learn more then feel free to proceed to section 2.
After completing the first section, you will be able to work with animations. Also, you can use animation libraries like React Spring. Happy animations & let’s get started.
Before you begin
This guide won’t teach you the concepts of React Native, else it will teach you react native animations. So, a prior knowledge of React Native is required.
Section 1 – Essentials of React Native animation
In this section, I included the three essential steps to work with animations. After completing this, you will be able to run animations in your app. I have also included a working example at the end.
Create a reference variable of Animated.Value
The first step involves the creation of animation variable. This variable defines the styling on the component throughout the whole animation lifecycle.
const animationVariable = useRef(new Animated.Value(0)).current;
I am setting the variable, animationVariable
with initial value of 0. This is it. Step completed.
Change the value of animationVariable
using Animated.Spring
or Animated.Timing
function
Since our variable is already defined, we now need a way to change the value of it. Why the animationVariable
value needs to be changed? Because the change in this value derives the changes in the style properties of components which ultimately animates them.
For example, suppose an image needs to be scaled twice its size. We can do that by changing the value of animationVariable and interpolate the changes with the amount of scaling we require. Not understood? Worry not, we will see that in third step.
To change the value of animation variable, we use Spring and Timing functions of Animated component.
Animated.spring(animationVariable, { toValue: 1, useNativeDriver: true, }).start();
Code Explanation –
Animated.spring |
This is the prebuilt function by React-Native to change the value of variable in a manner so that it gives the feel of spring while changing style values. Check other animation function here. |
toValue | It indicates the new value for our animationVariable . Remember, we set it to 0 in first step? Now the spring function will change it to 1. |
useNativeDriver | In React Native, our app runs on native thread and JS thread. Using this option will run our animation on native thread which will improve the performance. The only drawback is that few styles are supporting native drivers, as of now. Check the list of all supporting styles |
start | Calling start will run the animation. Means, animationVariable value will change from 0 to 1 in spring form within the time period defined by React-Native in Animated.spring method. |
Create interpolation of animationVariable
in styles of component to animate
Now we will use this animationVariable
to change the style of component according to how we wish to animate it. Like in our earlier example, suppose we want to scale an Image
or a View
, we will do –
<Animated.View style = {{ transform: [ { scale : animationVariable.interpolate({ inputRange: [0, 1], outputRange: [1, 2], }), }, ], }}></Animated.View>
Code Explanation
Animated.View |
No, you can’t run animation on simple components. You need special components provided by Animated component. So, we are using Animated.View . You can read more about it here. |
interpolate | Interpolate converts the animationVariable value into the required scale value. |
inputRange | It defines the range of value for animationVariable . Here it is changing from 0 to 1. |
outputRange | It is defining the value of scale for the corresponding animationVariable value. So, when animationVariable is 0, scale will be 1. When it is 1, scale will be 2. |
Now you know how React Native animation works. Here is an infographic to clear your understandings further.
Working Example
import React, {useRef} from 'react'; import {Animated, Button, View} from 'react-native'; const App = () => { const animationValue = useRef(new Animated.Value(0)).current; const runAnimationOnClick = () => { Animated.spring(animationValue, { toValue: 1, useNativeDriver: true, }).start(); } return ( <View> <Animated.View style = {{ height: 200, width: 200, backgroundColor: 'red', transform: [ { scale: animationValue.interpolate({ inputRange: [0, 1], outputRange: [1, 2], }), }, ], }} /> <Button title="Scale Up" onPress={runAnimationOnClick} /> </View> ); } export default App;
End of Section 1
In this tutorial we learned the three basic steps of working with React Native animation. First we create the animation variable. Second, we change the value of variable using spring or timing function. Third, we interpolate the variable into useful style values.
Section 2 – If you want to learn more about React Native animation
Point 1: You can initialize any value for your animationVariable. We set 0 but doesn’t mean you have to do the same.
Point 2: There are 6 components in react native which could be animated – Animated.View
, Animated.Image
, Animated.Text
, Animated.ScrollView
, Animated.FlatList
, Animated.SectionList
.
Point 3: There are few types of animation function like Animated.timing(), Animated.spring() and Animated.decay(). Code snippet for timing animation function is –
Animated.timing(animationValue, { toValue: 1, easing: Easing.back(), duration: 2000, useNativeDriver: true, }).start(({finished}) => {});
Note: React Native says that the default value of
useNativeDriver
is false, but actually you need to provide this property otherwise debugger will crash.
Easing defines the type of animation you want like bouncing, easeIn, easeOut, elastic etc.
{finished}
parameter in start function helps in determining whether the animation is completed successfully or not. Because the function within start acts as a callback. It gets called either when animation got completed or interrupted in the middle. So, in case when you want to run something only when animation is completed, there you can use finished
property within if
condition.
duration
defines how long will it take to change the value of animationValue
from current to toValue
. Like, in our case it will take 2000 ms (2 seconds) to change animationValue
from 0 to 1.
Overall in summary, our animation will run for 2 seconds using easing.back
(it will run the animation in opposite direction a bit and then move forward. Think of it like Lion taking few steps back before jumping. So, suppose you use this animation for scaling a View
from 1 to 2 then the View
first scale down a bit, like 0.9 and then go to 2).
Point 4: Sometimes you feel the need to combine animations together. For example, suppose you want to show 3 buttons in fadeIn style where 2nd button will start showing up only when first has reached half opacity. So, it will give the illusion of appearing buttons but with a delay. I will show this effect with code demo. There are 4 composing animations provided by React Native – Animated.delay(), Animated.parallel(), Animated.sequence(), Animated.stagger().
Point 4.1: Animated.sequence()
is used to run different animations one after the other. So, suppose there are three boxes and you want to move them one after the other then we will use Animated.sequence()
. See this code –
Animated.sequence([ Animated.timing(box1AnimationValue, { toValue: 1, duration: 1000, useNativeDriver: true, }), Animated.timing(box2AnimationValue, { toValue: 1, duration: 1000, useNativeDriver: true, }), ]).start()
Point 4.2: Animated.delay()
is used with Animated.sequence
and its purpose is to add a delay between two animations. For example, if you want to move the blue box after 1 second of completion of red box. Check this code snippet –
Animated.sequence([ Animated.timing(box1AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), Animated.delay(1000), Animated.timing(box2AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), ]).start()
Point 4.3: Animated.parallel()
is similar to Animated.sequence()
but here all the animations will run at the same time. Check out this code –
Animated.parallel([ Animated.timing(box1AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), Animated.timing(box2AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), ]).start()
Point 4.4: Animated.stagger()
is pretty interesting. It runs the animations in parallel but with a fixed delay. Like the second animation will start after the provided delay of starting of first animation. Check the code –
Animated.stagger(200, [ Animated.timing(box1AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), Animated.timing(box2AnimationVariable, { toValue: 1, duration: 1000, useNativeDriver: true, }), ]).start()
Code snippet for the button fading example is –
import * as React from 'react'; import { Animated, View, Button, Text, TouchableHighlight } from 'react-native'; export default function App() { const button1AnimationValue = React.useRef(new Animated.Value(0)).current; const button2AnimationValue = React.useRef(new Animated.Value(0)).current; const button3AnimationValue = React.useRef(new Animated.Value(0)).current; const buttonPressed = () => { button1AnimationValue.setValue(0); button2AnimationValue.setValue(0); button3AnimationValue.setValue(0); Animated.stagger(100, [ Animated.timing(button1AnimationValue, { toValue: 1, duration: 300, useNativeDriver: true, }), Animated.timing(button2AnimationValue, { toValue: 1, duration: 300, useNativeDriver: true, }), Animated.timing(button3AnimationValue, { toValue: 1, duration: 300, useNativeDriver: true, }), ]).start(({finished}) => {}) } return ( <View style={{alignItems: 'center'}}> <Animated.View style={{ marginTop: 5, marginBottom: 5, opacity: button1AnimationValue.interpolate({ inputRange: [0, 1], outputRange: [0, 1], }), }}> <Button title={'Button 1'} color={'red'} /> </Animated.View> <Animated.View style={{ marginTop: 5, marginBottom: 5, opacity: button2AnimationValue.interpolate({ inputRange: [0, 1], outputRange: [0, 1], }), }}> <Button title={'Button 2'} color={'cyan'} /> </Animated.View> <Animated.View style={{ marginTop: 5, marginBottom: 5, opacity: button3AnimationValue.interpolate({ inputRange: [0, 1], outputRange: [0, 1], }), }}> <Button title={'Button 2'} color={'green'} /> </Animated.View> <Button title={'Run Animation'} onPress={buttonPressed} /> <Text>Total fadein animation completes in 300ms but there is staggering delay of 100ms. So, second button will start fading in after 100ms of first button.</Text> </View> ); }
Point 5: You can set useNativeDriver: true
only in case of few styles like translate, scale, rotate, opacity but you can’t use native drivers for changing width and height of the components. In that case you will have to set it to false.
Point 6: interpolate
can be used for some non-numeric output ranges. For example, you can use it over colors and angles range. Check the code below –
backgroundColor: animationValue.interpolate({ inputRange: [0, 1], outputRange: ['rgb(255,0,0)', 'rgb(0,0,255)'], }),
This interpolation will change the background color from red to blue by passing through different color ranges in between.
Another example of interpolation of angles might look like this –
rotateX: animationValue.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '90deg'], }),
This interpolation will rotate the component in x direction from 0deg to 90deg.
Conclusion
That’s it, we reached the end. In this article we learned about how react native animation works and what are the different functions we need to remember. If you want to gain more in depth knowledge about each topic, you can refer to the official documentation of React Native from here – https://reactnative.dev/docs/animations