[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: View
, Text
, Image
, 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 fadeAnim
animated 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.timing
method. 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)
orEasing.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