How to create spinner in React Native with Renanimated 2
Creating spinner animation with reanimated. it shows how to use withRepeat and withTiming
Reanimated is a React Native library for creating animations and interactions which runs on the UI thread. Reanimated uses Turbo Modules which is part of re-architecture of NativeModules.
Before start coding lets learn some fundamentals of Reanimated 2
useSharedValue
: Reanimated 2 run animations in a separate thread. Shared values help to share these values among threads.
useAnimatedStyle
: This hook is really powerful part of new API of Reanimated 2. When we use this hook. if any shared value update inside this hooks. useAnimatedStyle react this and update the style and view.
Now lets focus how we create spinner animation with Reanimated 2
First of all, we imported all the necessary things.
import React, { useEffect } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
cancelAnimation,
Easing,
} from 'react-native-reanimated';
Then we have to create shared value and animated style. as you can see rotation.value
is a dependency. it means whenever value changed it will react to this and update the style.
const rotation = useSharedValue(0);
const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{
rotateZ: `${rotation.value}deg`,
},
],
};
}, [rotation.value]);
But also we need one more effect to run immediately our animation.
useEffect(() => {
rotation.value = withRepeat(
withTiming(360, {
duration: 1000,
easing: Easing.linear,
}),
-1
);
return () => cancelAnimation(rotation);
}, []);
rotation.value
is updated withTiming
animation. But we want this animation to loop forever. for this animation, we need to wrap withRepeat
animation. withRepeat
takes numberOfReps
as a second parameter. The first one is an animation. if the value is negative animations will repeat forever.
Lastly, we need to create Spinner
a view, our spinner basically circle with one side different color. if we animate the view, we will see spinning animation.
return (
<View style={styles.container}>
<Animated.View style={[styles.spinner, animatedStyles]} />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
height: '100%',
},
spinner: {
height: 60,
width: 60,
borderRadius: 30,
borderWidth: 7,
borderTopColor: '#f5f5f5',
borderRightColor: '#f5f5f5',
borderBottomColor: '#f5f5f5',
borderLeftColor: 'green',
},
});
Complete Code
import React, { useEffect } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Animated, {
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
cancelAnimation,
Easing,
} from 'react-native-reanimated';
const App = () => {
const rotation = useSharedValue(0);
const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{
rotateZ: `${rotation.value}deg`,
},
],
};
}, [rotation.value]);
useEffect(() => {
rotation.value = withRepeat(
withTiming(360, {
duration: 1000,
easing: Easing.linear,
}),
200
);
return () => cancelAnimation(rotation);
}, []);
return (
<View style={styles.container}>
<Animated.View style={[styles.spinner, animatedStyles]} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
height: '100%',
},
spinner: {
height: 60,
width: 60,
borderRadius: 30,
borderWidth: 7,
borderTopColor: '#f5f5f5',
borderRightColor: '#f5f5f5',
borderBottomColor: '#f5f5f5',
borderLeftColor: 'green',
},
});
export default App;