Hey there, I guess you decided to read this blog to learn a few things about React Native Animation and Hooks. You're in the right place.
We are going to make a basic rotation animation using the React Native Animated library. This will contain a "Twitter" logo at the center which will rotate to create a loading effect. We will incorporate the whole logic inside a hook. Let's start.
Step 1: Create a Loading Screen
We first need a loading screen to animate.
- Add a View with
flex: 1
, it will cover the whole screen. - Add Twitter logo (or any image you like) with a Loading... text.
- Place them at the center of the screen.
// App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Logo from './twitter.png';
export default function App() {
return (
<View style={styles.container}>
<Image
style={[styles.image]}
source={Logo}
resizeMode="contain"
/>
<Text style={styles.textMargin}>Loading tweets...</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
image: {
width: 100,
height: 100,
},
textMargin: {
marginTop: 30,
fontSize: 18,
},
});
You may have noticed that Image style is an array. This is because we are going to add styles to rotate the image in a while.
Step 2: Create useRotation
Hook
Create a file useRotation.js
and follow along. This will contain 4 steps:
1) Create Animated value
What's an Animated value ๐ค?
This will be the initial value created via the Animated
library. We will update this value with Animated
API and hook up the changes with styles of the Image to create a fluid animation.
import { Animated } from 'react-native';
import { useRef } from 'react';
export default function useRotation() {
const animation = useRef(new Animated.Value(0)).current;
return null;
}
We are using
useRef
hook as this ref object's current property is initialized as the given argument (Animated value) and persists throughout the component lifecycle. UsinguseState
is not recommended here.
2) Animate the value using Animated
API.
Animated API gives us a bunch of methods to mutate the animated value without much trouble. Some of the methods are timing
, spring
, decay
, etc. You can read more on the Official Documentation.
We will use Animated.timing()
to change the value in a particular duration and then Animated.delay()
to give a pause before starting to rotate again. Then we will use Animated.sequence()
to add these two animations in aa array to create a sequence.
import { Animated } from 'react-native';
import { useRef } from 'react';
export default function useRotation() {
const animation = useRef(new Animated.Value(0)).current;
function startAnimation() {
Animated.sequence([
Animated.timing(animation, {
toValue: 1,
duration: 750,
useNativeDriver: true,
}),
Animated.delay(300),
],
{ useNativeDriver: true })
.start(() => {
animation.setValue(0);
startAnimation();
});
}
return null;
}
Animated.sequence
takes an array of animated to execute one after another.
Animated.timing
takes the animated value (initialized 0 in this example) as the first argument and animate to toValue
provided (will change to 1 in this example) inside an object in the second argument with a specified duration
.
Animated.delay
takes a number of milliseconds which will delay the next animation.
After adding all these, we will start the animation by calling .start()
This start function takes a callback that will run after the animation is complete. We are using this to reset the animated value to 0 in order to start the animation again by calling startAnimation()
.
We are using
useNativeDriver: true
to send animation logic to the native side. This will ensure that our animation is not blocking JS thread and it runs smoothly.
3) Interpolate on the changes
Now, What's Interpolate?
interpolate()
function takes an inputRange
and maps it to the specified outputRange
. We will map the values 0, 1 with 0 degrees, 360 degree. As the value changes from 0 to 1, it will calculate relative values in degrees based on the change.
This means that 0 will give 0 degrees, 1 will give 360 degrees, and 0.5 will give 180 degrees as this is the half of both range. All other values in between are automatically calculated by this logic.
We will use this to interpolate our animated value and find a relative degree of rotation. Then we will return this degree from the hook.
import { Animated } from 'react-native';
import { useRef } from 'react';
export default function useRotation() {
const animation = useRef(new Animated.Value(0)).current;
function startAnimation() {
Animated.sequence([
Animated.timing(animation, {
toValue: 1,
duration: 750,
useNativeDriver: true,
}),
Animated.delay(300),
],
{ useNativeDriver: true })
.start(() => {
animation.setValue(0);
startAnimation();
});
}
//interpolate
const rotateInterpolation = animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});
return rotateInterpolation;
}
4) Start the animation โ๏ธ
We want this animation to run as soon as the screen is mounted. We can use useEffect
hook for this purpose. Add this line before interpolation code:
useEffect(() => {
startAnimation();
});
We are done with our animation logic. Now we just need to import this hook and use it inside App.js
Step 3: Import useRotation
Hook
Go to App.js and import the hook we just created. We will use the degrees returned by the hook to style the Twitter logo.
import React from 'react';
import { Animated, StyleSheet, Text, View } from 'react-native';
import Logo from './twitter.png';
//import hook
import useRotation from './useRotation';
export default function App() {
// get degrees from hook
const rotate = useRotation();
// transform image to rotate
const animatedStyle = { transform: [ { rotate } ] };
return (
<View style={styles.container}>
<Animated.Image
style={[styles.image, animatedStyle]}
source={Logo}
resizeMode="contain"
/>
<Text style={styles.textMargin}>Loading tweets...</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
image: {
width: 100,
height: 100,
},
textMargin: {
marginTop: 30,
fontSize: 18,
},
});
We have successfully added the useRotation
hook to our loading screen. The result looks like this ๐๐ผ.
You can check out the Live Demo here in expo snack.
TLDR
- We created a loading screen with an image and loading text at the center.
- We created
useRotation
hook to animate value and provide a relative degree of rotation - We imported that hook and used to rotate our logo.
If you liked reading this article. You might like my other article on react native animation. Do check Learn React Native Animation by building Circular Progress Bar.
That's it for now. Take care and stay safe.
Shad