React Native Animations – Info compilation

[Fuente: https://facebook.github.io/react-native/docs/animations]

[Fuente: https://scotch.io/@rakshitkrsoral/the-beginners-guide-to-using-react-native-animated-api]

[Fuente: https://www.raizlabs.com/dev/2018/03/react-native-animations-part1/]

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,
  • LayoutAnimation for animated global layout transactions.

Animated API

The Animated API is designed to make it very easy 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 simple start/stop methods to control time-based animation execution.

Animated exports four animatable component types: ViewTextImage, and ScrollView, 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:

import React from 'react';
import { Animated, Text, View } from 'react-native';

class FadeInView extends React.Component {
  state = {
    fadeAnim: new Animated.Value(0),  // Initial value for opacity: 0
  }

  componentDidMount() {
    Animated.timing(                  // Animate over time
      this.state.fadeAnim,            // The animated value to drive
      {
        toValue: 1,                   // Animate to opacity: 1 (opaque)
        duration: 10000,              // Make it take a while
      }
    ).start();                        // Starts the animation
  }

  render() {
    let { fadeAnim } = this.state;

    return (
      <Animated.View                 // Special animatable View
        style={{
          ...this.props.style,
          opacity: fadeAnim,         // Bind opacity to animated value
        }}
      >
        {this.props.children}
      </Animated.View>
    );
  }
}

// You can then use your `FadeInView` in place of a `View` in your components:
export default class App extends React.Component {
  render() {
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        <FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
        </FadeInView>
      </View>
    )
  }
}

Let’s break down what’s happening here. In the FadeInView constructor, a new Animated.Value called fadeAnim is initialized as part of state. 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 fadeAnimanimated value, which will update all of its dependent mappings (in this case, just 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 a 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 a 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,
}).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 simply 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,
  }),
  Animated.parallel([
    // after decay, in parallel:
    Animated.spring(position, {
      toValue: {x: 0, y: 0}, // return to start
    }),
    Animated.timing(twirl, {
      // and twirl
      toValue: 360,
    }),
  ]),
]).start(); // start the sequence group

If one animation is stopped or interrupted, then all other animations in the group are also stopped. Animated.parallel has a stopTogether option that can be set to false to disable this.

You can find a full list of composition methods in the Composing animations section of the Animated API reference.

Combining animated values

You can combine two animated values via addition, multiplication, division, or modulo to make a new animated value.

There are some cases where an animated value needs to invert another animated value for calculation. An example is inverting a scale (2x –> 0.5x):

const a = new Animated.Value(1);
const b = Animated.divide(1, a);

Animated.spring(a, {
  toValue: 2,
}).start();

Animation Drivers

Drivers are nodes in the graph that change Animated Values every frame. These are things like Animated.Timing, which drives a value over time, or Animated.Decay, which reduces a value every frame. We can connect an Animated.Event to an onScroll event: this drives a value as the user scrolls. We can start or stop a Driver, and connect it to other Animated Values or Drivers. When the driver updates each frame, its new value propagates down through the graph, updating its child Animation Drivers or Animated Values and eventually updating view properties.

Animated.decay(this.valueToAnimate, {
   velocity: 2.0,
   deceleration: 0.9
}).start();

In the decay animation above, our Animated Value starts at a velocity, and slows over time.

Define how the animated value will change over time

All animated values can be defined w.r.t change in time using Animated.timingmethod. Animated.timing has 3 common parameters that you can set:

  • Decay – starts with an initial velocity and gradually slows to a stop
  • Duration – starts the animation after a certain duration
  • Easing – To understand how easing functions work, you can prefer reading docs. On the surface level, these are the functions that allows developers to implement physically believable motion in React Native animations. By default, a typical easing function is linear, but if you want to override it to make something like Easing.sin(t) or Easing.bezier(x1, y1, x2, y2), you can add the line “import { ‘Easing’ } from ‘react-native'”

In the following example, I am fading animation over 200 ms.

Animated.timing(this.state.opacity, {toValue: 0, duration: 200})

Using Native Animations in Animated API

Changing an animation driver (like Animated.value, Animated.Timing or Animated.Spring) to use native animations is as easy as adding the property useNativeDriver: true. The same goes for an Animated.Event:

Animated.event( [{ ... }], { useNativeDriver: true } )

Note: – Always use Native Animations wherever possible in your React Native app.

Transform Operations

We convert Animated Values to new Animated Values through Transform operations.

Animated.add() , Animated.multiply() or Animated.interpolate() are examples of Transforms. We can run a Transform on any other node in the Animated graph: an animated value (new Animated.Value(42)).interpolate(...), or another transform: animatedPosition.interpolate(...).interpolate(...).

In one of our apps, we show a large illustration in the navbar, and minimize it as the screen scrolls. This gives the user more space to be productive. To do this, we pass the scroll distance (an Animated Value) as a prop on the NavBar component. The NavBar interpolates the scroll distance into a position or opacity, fading itself out and moving it up and off the screen.

ewewe
we
we
we
we
we
we