Introduction to Animations in React Native
Vladimir Novick
Frontend Developer & Architect
mail: vnovick@gmail.com
twitter: @VladimirNovick
github: vnovick
facebook: vnovickdev
I assume
you are familiar with
-
React
-
ReactNative
-
Basics of animation easing
Brief mechanics of RN
What RN Animations really are
LayoutAnimation = Native
Animated = requestAnimationFrame
LayoutAnimation
- Native Animations
- Applied to all style properties of component
- No need for specific values (heights/ widths)
- Less configurable
- Animates everything on next render
- If another setState triggers during animation this won't affect current animation
Pros:
Cons:
Animated
- Extremely configurable
- Can target very specific components
- Utilizes requestAnimationFrame to animate the values
- If setState takes time animations can stutter
Pros:
Cons:
LayoutAnimation
// enable layout animation for Android in component constructor
if (Platform.OS === 'android') {
UIManager
.setLayoutAnimationEnabledExperimental(true)
}
Just works
LayoutAnimation Basic usage
LayoutAnimation
onPress(index) {
const {
easeInEaseOut,
spring,
linear
} = LayoutAnimation.Presets;
LayoutAnimation.configureNext(
easeInEaseOut
// spring
// linear
)
this.setState({ index });
}
renderButton(index) {
return (
<TouchableOpacity
key={'button' + index}
style={styles.button}
onPress={() => this.onPress(index)}>
<Text>{index}</Text>
</TouchableOpacity>
);
}
render() {
const { redStyle, greenStyle, blueStyle } = this.getStyleByIndex(this.state.index)
return (
<View style={styles.container}>
<View style={styles.topButtons}>
{this.renderButton(0)}
{this.renderButton(1)}
{this.renderButton(2)}
</View>
<View style={styles.content}>
<View style={{flexDirection: 'column', flex: 1}}>
<View style={[redStyle, {backgroundColor: 'red'}]}/>
<View style={[greenStyle, {backgroundColor: 'green'}]}/>
<View style={[blueStyle, {backgroundColor: 'blue'}]}/>
</View>
</View>
</View>
);
}
LayoutAnimation API
configureNext - configures LayoutAnimation for next render
create - helper for custom animation creation
LayoutAnimation API
LayoutAnimation beyond Presets
easeInEaseOut Preset
easeInEaseOut: create(
300, Types.easeInEaseOut, Properties.opacity
)
Property to animate out of:
Type of animation out of:
TypesEnum = {
spring: true,
linear: true,
easeInEaseOut: true,
easeIn: true,
easeOut: true,
keyboard: true,
}
PropertiesEnum = {
opacity: true,
scaleXY: true,
};
duration
LayoutAnimation beyond Presets
Linear Preset
linear: create(
500, Types.linear, Properties.opacity
)
spring Preset
spring: {
duration: 700,
create: {
type: Types.linear,
property: Properties.opacity,
},
update: {
type: Types.spring,
springDamping: 0.4,
},
delete: {
type: Types.linear,
property: Properties.opacity,
},
}
LayoutAnimation
custom animations
const CustomLayoutAnimation = {
duration: 1000,
create: {
delay: 1000,
type: LayoutAnimation.Types.spring,
property: LayoutAnimation.Properties.scaleXY,
springDamping: 0.2,
initialVelocity: 1
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.scaleXY
},
delete: {
type: LayoutAnimation.Types.easeOut,
property: LayoutAnimation.Properties.opacity
},
};
Animation to execute on initial render
Animation to execute state update
Animation to execute when component is destroyed
LayoutAnimation
custom animations
onPress(index) {
LayoutAnimation.configureNext(CustomLayoutAnimation);
this.setState({index: index});
}
renderButton(index) {
return (
<TouchableOpacity key={'button' + index} style={styles.button} onPress={() => this.onPress(index)}>
<Text>{index + 1}</Text>
</TouchableOpacity>
);
}
renderCircle(key) {
var size = 50;
return (
<View key={key} style={{width: size, height: size, borderRadius: size / 2.0, backgroundColor: 'yellow', margin: 20}}/>
);
}
render() {
var circles = [];
for (var i = 0; i < (1 + this.state.index); i++) {
circles.push(this.renderCircle(i));
}
return (
<View style={styles.container}>
<View style={styles.topButtons}>
{this.renderButton(0)}
{this.renderButton(1)}
{this.renderButton(2)}
</View>
<View style={styles.content}>
<View style={styles.circleContainer}>
{circles}
</View>
</View>
</View>
);
}
Animated
Utilizes requestAnimationFrame to animate the values and setNativeProps in order to send values to the native world
Animated value types:
Animated components
- Animated.View
- Animated.Text
- Animated.Image
- createAnimatedComponent(Custom Component)
Animated.Value
Animated.ValueXY
timing/spring/decay/sequence/parallel/stagger/delay/event
Animated functions:
Animated API
Animated.Value
In order to create a simple value that can be animated we need to create a new value with
new Animated.Value(0)
Value cannot be object or array. It must be simple value.
Actual value is shielded inside Animated.Value and can be passed to style or other native prop on Animated components
Important!
Consider this
class Circle extends Component {
constructor(props){
super(props);
this.state = {
opacity: new Animated.Value(0)
}
}
componentDidMount(){
Animated.timing(
this.state.opacity,
{
toValue: 50,
duration: 10000
}
).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: size,
borderRadius: size / 2,
backgroundColor: 'coral',
margin: 20
}
return (
<Animated.View
key={this.props.id}
style={{
...circleStyle,
opacity: this.state.opacity
}}
/>
);
}
}
Animated.Value API
- setValue - let's you control animation values without triggering animations
- addListener/removeListener - attach listener to animation value update
- stopAnimation - stops animation in the middle of execution
Animated.ValueXY
In order to create a {x: 0, y:0 } value that can be animated we need to create a new value with
new Animated.ValueXY({x: 0, y: 0})
Usually used when dealing with component position/gestures
Actual value is shielded inside Animated.ValueXY and can be passed to style or other native prop on Animated components
Reasons to use
Animated.ValueXY API
getLayout() ->
getTranslateTransform() ->
{
left: this._animatedValue.x,
top: this._animatedValue.y
}
{transform: [
{
translateX:
this._animatedValue.x
},
{
translateY:
this._animatedValue.y
}
]}
setOffset - sets base offset above value. This method is also present in Animated.Value
The power of Interpolation
Interpolate is a function that gives us ability to bind to Animated.Value and change our output.
constructor(props){
super(props);
this._animatedXY = new Animated.ValueXY({ x: 0, y: 0});
}
componentDidMount(){
Animated.timing(
this._animatedXY,
{
toValue: 100,
duration: 1000
}).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: this._animatedXY.y.interpolate({
inputRange: [0, 100],
outputRange: [0, 50]
}),
borderRadius: size / 2,
margin: 20,
backgroundColor: this._animatedXY.x.interpolate({
inputRange: [0, 100],
outputRange: ['coral', 'blue']
})
}
return (
<Animated.View
key={this.props.id}
style={{
...circleStyle
}}
/>
);
}
Extrapolation
When interpolating values you have to specify how to extrapolate them.
Extrapolation
Three types of extrapolation:
- extend - (default) - extend interpolation beyond inputRange
- clamp: - stop interpolation when reached inputRange
- identity: when you hit inputRange boundary bypass everything and assign a value
componentDidMount(){
Animated.timing(
this._animatedXY,
{
toValue: 1000,
duration: 1000
}
).start();
}
render(){
let size = 50;
const circleStyle = {
width: size,
height: this._animatedXY.y.interpolate({
inputRange: [0, 100],
outputRange: [0, 50],
extrapolate: 'extend',
// extrapolate: 'clamp',
// extrapolate: 'identity',
}),
borderRadius: size / 2,
margin: 20,
backgroundColor: this._animatedXY.x.interpolate({
inputRange: [0, 100],
outputRange: ['coral', 'blue']
})
}
Animated Functions Overview
- timing - animates value over a set amount of time
- spring - animate from start to end without seting time, but setting other properties like velocity, speed, tension e.t.c
- decay - animate with specified velocity and apply deceleration to it
- sequence - sequence one animation after another
Animated Functions Overview
- parallel - runs several animations in parallel
- stagger - runs several animations with some delay between them
- delay - just like timing, but without animating anything just ways specified number of milliseconds
- event - helper function to map event data to Animated values
Resources to check
react@90min.com
Introduction to Animation in React Native
By vladimirnovick
Introduction to Animation in React Native
- 2,238