Simple UI Animations with react-native

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>
    )
  }
}

Leave a Reply