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, 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.springThis 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.
toValueIt 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.
useNativeDriverIn 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
startCalling 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.ViewNo, 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.
interpolateInterpolate converts the animationVariable value into the required scale value.
inputRangeIt defines the range of value for animationVariable. Here it is changing from 0 to 1.
outputRangeIt 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.

Infographic of how animation works in react native

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;
Open Live Demo

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()
Open Live Demo

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()
Open Live Demo

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()
Open Live Demo

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()
Open Live Demo

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>
  );
}
Open Live Demo

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