Facebook’s react-native platform has an animation API that lets you animate Text, Image or View components. You can animate properties of the components, then make them play on an event, chain them together sequentially, or play them all together.
Styles you can animate:
Here are some stylesheet properties of components that you can animate:
- Opacity
- Width
- Height
- Translation offsets
- Rotation
Animation variables:
One-dimensional values to be animated (such as opacity or height) are stored in an Animated.Value
object, while two-dimensional values (such as XY translation) are stored in an Animated.ValueXY
object. These are initialized like this:
import { 'Animated' } from react-native;
this.state = {
opacityValue: new Animated.Value(255),
translation: new Animated.ValueXY(0, 0)
};
Specifying animation types
There are three ways to procedurally change the value of an animation variable: spring
, decay
, and toValue
. To call these functions, you must specify which variable is being configured, and a configuration object, with parameters described below. In addition, the target value at the end of the animation is called toValue
.
Spring
is straightforward to use; it causes the value to bounce, and you can optionally set the friction (“bounciness”) and tension (“speed”).
Decay
is also straightforward to use; it’s simply an exponential decay function where you set the rate of decay (e.g., 0.97) and the initial velocity, which is required.
timing
has 3 parameters that you can set: delay and duration are obvious, but the third one, easing, requires a deeper understanding to use. The default easing function is linear, but if you want to override it to something like Easing.sin(t) or Easing.bezier(x1, y1, x2, y2), you must add/integrate the line “import { ‘Easing’ } from ‘react-native'” to the top of your source code. The easing functions you can use are here.
Example to get something to fade out over 200ms:
Animated.timing(this.state.opacity, {toValue: 0, duration: 200})
You can also set the value directly simply by calling Animated.setValue()
.
Assigning animation variables to a component
Using the above example of opacity, just set a stylesheet property:
render() {
let myStyle = {
opacity: this.state.opacityValue,
};
return (
<Animated.View style={myStyle}>
<Text>Woooo!</Text>
</Animated.View>
);
}
Note how <Animated.View>
is used instead of <View>
. For Animated.ValueXY
variables, you may have to get the X and Y values directly by accessing myXYValue.x._value
and myXYValue.y._value
.
Calling the animation
To start an animation, you simply call .start()
on the Animated object, optionally passing a callback function.
Animated.timing(this.state.opacity,
{toValue: 0, duration: 200}).start(() =>
Alert.alert('Animation done!'))
The callback function is how you get animations to loop. At the time of writing, react-native does not have built-in parameters for looping an animation.
Sequential and parallel animations
You can start animations in sequence or in parallel by calling Animated.sequence()
or Animated.parallel()
with an array of Animation calls. It’s better explained by an example:
Animated.parallel([
Animated.spring(this.state.heartSize, { toValue: 1, friction: 0.7, tension: 0.4 }),
Animated.spring(this.state.circleSize, { toValue: 0.5, friction: 1.0, tension: 0.3 }),
]).start();
Summary
- Create Animation variables by using
Animated.Value()
- Assign Animation variables to stylesheet properties attached to
<Animated.View>
, <Animated.Text>
or <Animated.Image>
tags
- Configure an animation by calling
Animated.timing()
, Animated.spring()
, or Animated.decay()
- Start an animation by calling
.start()
on the configured animation
- Start animations in sequence or parallel by wrapping multiple animations in an array and passing the array as a parameter to
Animation.sequence()
or Animation.parallel()
- For more details, see the Animated API reference or the react-native Animations guide
Full code example
import React, { Component } from 'react';
import { Alert, Animated, Button, Text, View } from 'react-native';
export default class AnimationView extends Component {
constructor(props) {
super(props);
this.state = {
opacityValue: new Animated.Value(1),
heartSize: new Animated.Value(0.5),
circleSize: new Animated.Value(1.0),
};
}
render() {
let textStyle = {
opacity: this.state.opacityValue
};
let heartStyle = {
transform: [{scale: this.state.heartSize}]
}
let circleStyle = {
transform: [{scale: this.state.circleSize}]
}
return (
<View>
<View>
<Button onPress={() => {
Animated.timing(this.state.opacityValue, { toValue: 0, duration: 1000 }).start(() => Alert.alert('Animation done!'));
}}
title="Fade text away"
color="powderblue" />
<View style={{backgroundColor: "powderblue"}}>
<Animated.Text style={textStyle}>Fade away</Animated.Text>
</View>
</View>
<View>
<Button onPress={() => {
Animated.parallel([
Animated.spring(this.state.heartSize, { toValue: 1, friction: 0.7, tension: 0.4 }),
Animated.spring(this.state.circleSize, { toValue: 0.5, friction: 1.0, tension: 0.3 }),
]).start();
}}
title="Initiate love"
color="pink" />
<View style={{flexDirection: "row", backgroundColor: "white"}}>
<Animated.Image style={heartStyle} source={require('./heart.png')}/>
<Animated.Image style={circleStyle} source={require('./circle.png')}/>
</View>
</View>
</View>
)
}
}