With the advancement in UI/UX, the importance of animations in web/mobile applications has increased since they contribute to a great user experience. Animations enhance the user experience with the help of visual communication, simplify complex information, guide user attention, add emotional appeal, aid in storytelling, and promote interactivity. Several third-party libraries allow us to add animations in React Native applications. For example, react-native-animatable
, react-native-motion
, Lottie
and react-native-reanimated
. However, React Native provides us with the Animated API that makes our life easier regarding animations.
The Animated API in React Native allows developers to create and manage animated components and animations. To summarize its functionality and key features:
Animated values: Developers can create animated values like numbers or colors and link them to UI component properties. These values can be updated over time to drive animations.
Interpolation: Animated values can be interpolated to map input ranges to output ranges. This allows developers to create animations that smoothly change properties based on the progress of the animation.
Animated components: React Native provides animated versions of common components, such as Animated.View
, Animated.Text
, and Animated.Image
. These components can be animated by linking their properties to animated values.
Animation functions: The Animated API offers functions like Animated.timing
for timing-based animations, Animated.spring
for spring-based animations, and Animated.sequence
and Animated.parallel
for combining multiple animations.
Animation methods: The Animated
library provides methods to control and manage animations, such as start()
, stop()
, and addListener()
. These methods allow developers to control the lifecycle and behavior of animations.
We can use any of the above-mentioned features of Animated API along with its components, Animated.View
and Animated.Text
, to animate any view of the application. The two most common animation functions are Animated.timing
and Animated.spring
, so we will use one of these for our examples.
Let’s see an example where we have slightly bounced a ball outward using the spring animation, along with the animated view.
import {StyleSheet, Animated, Button, View } from 'react-native'; import {useRef} from "react"; function App() { const move = useRef(new Animated.Value(0)).current; const animation = () => { Animated.spring(move, { toValue: 2, friction: 3, useNativeDriver: true, }).start(); }; return ( <View> <Animated.View style={[styles.ball, { transform: [{scale: move}]}]} /> <View style={{flex: 1, alignItems: 'center', justifyContent: 'center', marginTop: 150}}> <Button title="Spring the ball" onPress={animation} /> </View> </View> );} export default App; const styles = StyleSheet.create({ ball: { height: 100, width: 100, borderRadius: 150/2, backgroundColor: 'red', marginTop: 150, marginRight: 'auto', marginBottom: 'auto', marginLeft: 'auto' } });
Line 1: We import Animated
from react-native
.
Line 5: We initialize the animation value, move
, using Animated.Value
to . The ball animates as per this value.
Lines 7—13: We create a function, animation
, which will cause the spring animation, that is, make the ball bounce outward.
Line 8: We initialize the spring animation function, Animated.spring(move, configurations)
, which takes the animated value to be changed as the first argument and certain configurations as the second argument.
Line 9: This is the value we want our animation value, move
, to change to. It changes the value of move
from to .
Line 17: We pass the animation value to the Animated.View
component. This renders the animation.
Line 19: We create a button to make the call to the animation function once clicked.
Let’s see an example where we’ve animated the text using the timing animation. The text will fade in.
import {StyleSheet, Animated, Button, View } from 'react-native'; import {useRef} from "react"; function App() { const fade = useRef(new Animated.Value(0)).current; const animation = () => { Animated.timing(fade, { toValue: 1, duration: 2000, useNativeDriver: true, }).start(); }; return ( <View> <Animated.Text style={[styles.text, {opacity:fade}]}>Hello World</Animated.Text> <View style={{flex: 1, alignItems: 'center', justifyContent: 'center', marginTop: 100}}> <Button title="Fade In Text" onPress={animation} /> </View> </View> );} export default App; const styles = StyleSheet.create({ text:{ marginTop:50, marginLeft:150, color: '#000080', fontSize: 80 } });
Line 1: We import Animated
from react-native
.
Line 5: We initialize the animation value, fade
, to using Animated.Value
. The text fades in as per this value.
Lines 7—13: We create a function, animation
, that will cause the text to fade in because of the timing animation.
Line 8: We initialize the spring animation function, Animated.timing(fade, configurations)
, which takes the animated value to be changed as the first argument and certain configurations as the second argument.
Line 9: This is the value we want our animation value, fade
, to change to. It changes the value of fade
from to .
Line 10: This is the duration of the animation. We have set it to milliseconds.
Line 17: We pass the animation value to the Animated.Text
component. This renders the animation.
Line 19: We create a button to make the call to the animation function once clicked.
As our final example, we’ve created a demo application that will demonstrate the use of multiple animated methods, along with its components Animated.View
and Animated.Text
.
Click “Run” to execute the code. Once the server starts, you can click the URL next to “Your app can be found at:” to view the application in the new browser tab.
import Night from "./components/Night" import Shooting from "./components/Shootingstar" import {StyleSheet, Animated, TouchableOpacity, Text, View } from 'react-native'; import { useEffect, useRef, useState } from "react"; function App() { const [clicked, setClick] = useState(false); const [mode, setMode] = useState(''); const [bg, setBG] = useState('white'); const fade = useRef(new Animated.Value(0)).current; const move = useRef(new Animated.Value(-1)).current; const dec = useRef(new Animated.Value(-200)).current; const textmove = useRef(new Animated.Value(0)).current; const animation1 = () => { setClick(!clicked) setBG('#151931') setMode('first') Animated.sequence([ Animated.timing(fade, { toValue: 1, duration: 2000, useNativeDriver: true, }), Animated.spring(move, { toValue: 0.75, friction: 3, useNativeDriver: true, }) ]).start(); }; const animation2 = () => { setClick(!clicked) setBG('#151931') setMode('second') Animated.decay(dec, { toValue: 300, duration: 5000, velocity: 1.5, deceleration: 0.998, useNativeDriver: true }).start(); }; const removeAnimation1 = () => { setBG('white') setClick(!clicked) setMode('') Animated.sequence([ Animated.spring(move, { toValue: -1, useNativeDriver: true, }), Animated.timing(fade, { toValue: 0, useNativeDriver: true, }) ]).start(); }; const removeAnimation2 = () => { setClick(!clicked) setBG('white') setMode('') Animated.timing(dec, { toValue: -200, useNativeDriver: true }).start(); }; useEffect(() => { Animated.spring(textmove, { toValue: 1, duration: 1000, useNativeDriver: true, }).start(); }, [textmove]); return ( <View style={{backgroundColor: bg, height: '100vh', paddingTop:'80px'}}> {mode === 'first' && <Night fade={fade} move={move} />} {mode === 'second' && <Shooting dec={dec} />} {mode === '' && <> <View> <Animated.Text style={[styles.text1,{ transform: [{scale: textmove}]}]}>Hello! 👋</Animated.Text> </View> </>} {clicked && <> <View style={styles.container3}> {mode === 'first' && <TouchableOpacity style={[styles.button, {backgroundColor: 'grey'}]} onPress={removeAnimation1}> <Text style={{ color:'white'}}>Back</Text> </TouchableOpacity>} {mode === 'second' && <TouchableOpacity style={[styles.button, {backgroundColor: 'grey'}]} onPress={removeAnimation2}> <Text style={{ color:'white'}}>Back</Text> </TouchableOpacity>} </View> </>} {!clicked && <> <View style={styles.container3}> <TouchableOpacity style={[styles.button, {backgroundColor:'#000080'}]} onPress={animation1}> <Text style={{ color:'white'}}>Show me the starry night</Text> </TouchableOpacity> <TouchableOpacity style={[styles.button, {backgroundColor:'#000080'}]} onPress={animation2}> <Text style={{ color:'white'}}>Show me the shooting star</Text> </TouchableOpacity> </View> </>} </View> );} export default App; const styles = StyleSheet.create({ container1:{ flexDirection: 'row', flexWrap: 'wrap', flex: 1, justifyContent: 'space-around' }, container2:{ flexDirection: 'row', flexWrap: 'wrap', flex: 1, justifyContent: 'space-between', marginTop: 200, }, container3:{ flexDirection: 'row', flexWrap: 'wrap', flex: 1, justifyContent: 'space-around', marginRight:'400px', marginLeft:'400px' }, text1:{ marginLeft:'600px', color: '#000080', fontSize: 80 }, button: { alignItems: 'center', height: 40, width: 200, marginTop: 120, justifyContent: 'center', borderRadius:'10px' }, });
The execution of the code above displays the main application page that demonstrates the use of Animated.Text
and Animated.spring
. The main page has two buttons: one to show the starry night and the other to show the shooting star. The starry night shows the use of Animated.View
, Animated.timing
, Animated.spring
and Animated.sequence
. On the other hand, the shooting star demonstrates the uses of Animated.View
, and Animated.decay
.
Free Resources