Animations
Animations are very important to create a great user experience. Stationary objects must overcome inertia as they start moving. Objects in motion have momentum and rarely come to a stop immediately. Animations allow you to convey physically believable motion in your interface.
React Native provides two complementary animation systems: Animated for granular and interactive control of specific values, and LayoutAnimation for animated global layout transactions.
Animated API
The Animated API is designed to concisely express a wide variety of interesting animation and interaction patterns in a very performant way. Animated focuses on declarative relationships between inputs and outputs, with configurable transforms in between, and start/stop methods to control time-based animation execution.
Animated exports six animatable component types: View, Text, Image, ScrollView, FlatList and SectionList, but you can also create your own using Animated.createAnimatedComponent().
For example, a container view that fades in when it is mounted may look like this:
- TypeScript
- JavaScript
Let's break down what's happening here. In the FadeInView render method, a new Animated.Value called fadeAnim is initialized with useRef. The opacity property on the View is mapped to this animated value. Behind the scenes, the numeric value is extracted and used to set opacity.
When the component mounts, the opacity is set to 0. Then, an easing animation is started on the fadeAnim animated value, which will update all of its dependent mappings (in this case, only the opacity) on each frame as the value animates to the final value of 1.
This is done in an optimized way that is faster than calling setState and re-rendering. Because the entire configuration is declarative, we will be able to implement further optimizations that serialize the configuration and runs the animation on a high-priority thread.
Configuring animations
Animations are heavily configurable. Custom and predefined easing functions, delays, durations, decay factors, spring constants, and more can all be tweaked depending on the type of animation.
Animated provides several animation types, the most commonly used one being Animated.timing(). It supports animating a value over time using one of various predefined easing functions, or you can use your own. Easing functions are typically used in animation to convey gradual acceleration and deceleration of objects.
By default, timing will use an easeInOut curve that conveys gradual acceleration to full speed and concludes by gradually decelerating to a stop. You can specify a different easing function by passing an easing parameter. Custom duration or even a delay before the animation starts is also supported.
For example, if we want to create a 2-second long animation of an object that slightly backs up before moving to its final position:
Animated.timing(this.state.xPosition, {
toValue: 100,
easing: Easing.back(),
duration: 2000,
useNativeDriver: true,
}).start();
Take a look at the Configuring animations section of the Animated API reference to learn more about all the config parameters supported by the built-in animations.
Composing animations
Animations can be combined and played in sequence or in parallel. Sequential animations can play immediately after the previous animation has finished, or they can start after a specified delay. The Animated API provides several methods, such as sequence() and delay(), each of which take an array of animations to execute and automatically calls start()/stop() as needed.
For example, the following animation coasts to a stop, then it springs back while twirling in parallel:
Animated.sequence([
// decay, then spring to start and twirl
Animated.decay(position, {
// coast to a stop
velocity: {x: gestureState.vx, y: gestureState.vy}, // velocity from gesture release
deceleration: 0.997,
useNativeDriver: true,
}),
Animated.parallel([
// after decay, in parallel:
Animated.spring(position, {
toValue: {x: 0, y: 0}, // return to start
useNativeDriver: true,
}),
Animated.timing(twirl, {
// and twirl
toValue: 360