Skip to content

React Native - Animations

React Native provides powerful APIs for creating animations. This chapter focuses on the Animated API for fine-grained control over animated values, and briefly mentions LayoutAnimation for simpler transitions. We’ll use functional components and Hooks.

The Animated API allows you to create time-based animations (like Animated.timing), spring-based animations (Animated.spring), or decay animations (Animated.decay). You typically animate specific style properties of special Animated components (e.g., Animated.View, Animated.Text, Animated.Image).

We’ll create an example where a box changes its width and height when pressed.

AnimatedBox.js

import React, { useRef, useState } from 'react';
import { View, StyleSheet, Animated, TouchableOpacity, Text } from 'react-native';
const AnimatedBox = () => {
// useRef to store Animated values, persisting them across re-renders
const animatedWidth = useRef(new Animated.Value(100)).current;
const animatedHeight = useRef(new Animated.Value(100)).current;
const animatedOpacity = useRef(new Animated.Value(1)).current;
const [isExpanded, setIsExpanded] = useState(false);
const animateBox = () => {
const newWidth = isExpanded ? 100 : 200;
const newHeight = isExpanded ? 100 : 200;
const newOpacity = isExpanded ? 1 : 0.5;
// Parallel animations
Animated.parallel([
Animated.timing(animatedWidth, {
toValue: newWidth,
duration: 500, // milliseconds
useNativeDriver: false, // 'true' for better performance on non-layout properties
}),
Animated.timing(animatedHeight, {
toValue: newHeight,
duration: 700,
useNativeDriver: false,
}),
Animated.timing(animatedOpacity, {
toValue: newOpacity,
duration: 700,
useNativeDriver: true, // Opacity can use native driver
})
]).start(() => {
setIsExpanded(!isExpanded); // Toggle state after animation completes
});
};
// Create an animated style object
const animatedStyle = {
width: animatedWidth,
height: animatedHeight,
opacity: animatedOpacity,
};
return (
<View style={styles.container}>
<TouchableOpacity onPress={animateBox}>
<Animated.View style={[styles.box, animatedStyle]} />
</TouchableOpacity>
<Text style={styles.instructionText}>
Tap the box to {isExpanded ? 'collapse' : 'expand'} it.
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f0f0f0',
},
box: {
backgroundColor: 'royalblue',
// Initial dimensions are set by Animated.Value
},
instructionText: {
marginTop: 20,
fontSize: 16,
color: '#333',
}
});
export default AnimatedBox;
  • useRef and Animated.Value: We initialize Animated.Values inside useRef to ensure they persist across renders without being recreated. animatedWidth.current gives access to the Animated.Value instance.
  • Animated.timing: Creates an animation that transitions a value over a specified duration. Other types include Animated.spring (physics-based spring) and Animated.decay (initial velocity gradually slows to a stop).
  • Animated.parallel: Runs multiple animations simultaneously. Other combinators include Animated.sequence (animations one after another) and Animated.stagger (staggered start times).
  • start(): Begins the animation. It can take an optional callback that fires upon completion.
  • Animated.View: A special component that can have its style properties animated. You must use Animated.View, Animated.Text, Animated.Image, etc., or create your own animatable components using Animated.createAnimatedComponent().
  • useNativeDriver: true: For performance, offloads animations to the native thread. This only works for non-layout properties (like transform, opacity). Layout properties (width, height, margin, padding, top, left, etc.) must use useNativeDriver: false (default) and run on the JS thread.

When you tap the blue box, it will smoothly animate its width, height, and opacity. Tapping again will reverse the animation.

LayoutAnimation provides a simpler way to animate transitions when layout properties change (e.g., due to state updates). It animates views to their new positions when the next layout calculation happens.

LayoutAnimationExample.js

import React, { useState } from 'react';
import {
View, StyleSheet, TouchableOpacity, Text,
LayoutAnimation, UIManager, Platform
} from 'react-native';
// Enable LayoutAnimation for Android (iOS is enabled by default)
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
const LayoutAnimationExample = () => {
const [boxSize, setBoxSize] = useState(100);
const [isToggled, setIsToggled] = useState(false);
const toggleBox = () => {
// Configure the animation type.
// Options: LayoutAnimation.Presets.easeInEaseOut, .linear, .spring
// Or define custom animation: LayoutAnimation.configureNext(config);
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setBoxSize(isToggled ? 100 : 200);
setIsToggled(!isToggled);
};
return (
<View style={styles.container}>
<TouchableOpacity onPress={toggleBox}>
<View style={[styles.box, { width: boxSize, height: boxSize }]} >
<Text style={styles.boxText}>Tap Me</Text>
</View>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5fcff',
},
box: {
backgroundColor: 'mediumseagreen',
justifyContent: 'center',
alignItems: 'center',
},
boxText: {
color: 'white',
fontWeight: 'bold'
}
});
export default LayoutAnimationExample;

LayoutAnimation is simpler for global layout changes but less flexible than Animated. You call LayoutAnimation.configureNext() before the state change that causes the re-layout.

  • Use Animated for complex, interactive animations, or when you need fine-grained control over animation values and sequences.
  • Use LayoutAnimation for simple, fire-and-forget animations of layout properties triggered by state changes.
  • For more advanced and performant animations, especially gesture-based ones, consider libraries like React Native Reanimated and React Native Gesture Handler.

Explore the official animation guides: https://reactnative.dev/docs/animations and https://reactnative.dev/docs/layoutanimation.