diff --git a/Libraries/Animated/Animated.js b/Libraries/Animated/Animated.js
index ec4977f3b..1a357f033 100644
--- a/Libraries/Animated/Animated.js
+++ b/Libraries/Animated/Animated.js
@@ -503,6 +503,12 @@ type ValueListenerCallback = (state: {value: number}) => void;
var _uniqueId = 1;
+/**
+ * Standard value for driving animations. One `Animated.Value` can drive
+ * multiple properties in a synchronized fashion, but can only be driven by one
+ * mechanism at a time. Using a new mechanism (e.g. starting a new animation,
+ * or calling `setValue`) will stop any previous ones.
+ */
class AnimatedValue extends AnimatedWithChildren {
_value: number;
_offset: number;
@@ -526,6 +532,10 @@ class AnimatedValue extends AnimatedWithChildren {
return this._value + this._offset;
}
+ /**
+ * Directly set the value. This will stop any animations running on the value
+ * and udpate all the bound properties.
+ */
setValue(value: number): void {
if (this._animation) {
this._animation.stop();
@@ -534,15 +544,29 @@ class AnimatedValue extends AnimatedWithChildren {
this._updateValue(value);
}
+ /**
+ * Sets an offset that is applied on top of whatever value is set, whether via
+ * `setValue`, an animation, or `Animated.event`. Useful for compensating
+ * things like the start of a pan gesture.
+ */
setOffset(offset: number): void {
this._offset = offset;
}
+ /**
+ * Merges the offset value into the base value and resets the offset to zero.
+ * The final output of the value is unchanged.
+ */
flattenOffset(): void {
this._value += this._offset;
this._offset = 0;
}
+ /**
+ * Adds an asynchronous listener to the value so you can observe updates from
+ * animations or whathaveyou. This is useful because there is no way to
+ * syncronously read the value because it might be driven natively.
+ */
addListener(callback: ValueListenerCallback): string {
var id = String(_uniqueId++);
this._listeners[id] = callback;
@@ -557,6 +581,30 @@ class AnimatedValue extends AnimatedWithChildren {
this._listeners = {};
}
+ /**
+ * Stops any running animation or tracking. `callback` is invoked with the
+ * final value after stopping the animation, which is useful for updating
+ * state to match the animation position with layout.
+ */
+ stopAnimation(callback?: ?(value: number) => void): void {
+ this.stopTracking();
+ this._animation && this._animation.stop();
+ this._animation = null;
+ callback && callback(this.__getValue());
+ }
+
+ /**
+ * Interpolates the value before updating the property, e.g. mapping 0-1 to
+ * 0-10.
+ */
+ interpolate(config: InterpolationConfigType): AnimatedInterpolation {
+ return new AnimatedInterpolation(this, Interpolation.create(config));
+ }
+
+ /**
+ * Typically only used internally, but could be used by a custom Animation
+ * class.
+ */
animate(animation: Animation, callback: ?EndCallback): void {
var handle = InteractionManager.createInteractionHandle();
var previousAnimation = this._animation;
@@ -576,27 +624,22 @@ class AnimatedValue extends AnimatedWithChildren {
);
}
- stopAnimation(callback?: ?(value: number) => void): void {
- this.stopTracking();
- this._animation && this._animation.stop();
- this._animation = null;
- callback && callback(this.__getValue());
- }
-
+ /**
+ * Typically only used internally.
+ */
stopTracking(): void {
this._tracking && this._tracking.__detach();
this._tracking = null;
}
+ /**
+ * Typically only used internally.
+ */
track(tracking: Animated): void {
this.stopTracking();
this._tracking = tracking;
}
- interpolate(config: InterpolationConfigType): AnimatedInterpolation {
- return new AnimatedInterpolation(this, Interpolation.create(config));
- }
-
_updateValue(value: number): void {
this._value = value;
_flush(this);
@@ -607,6 +650,45 @@ class AnimatedValue extends AnimatedWithChildren {
}
type ValueXYListenerCallback = (value: {x: number; y: number}) => void;
+
+/**
+ * 2D Value for driving 2D animations, such as pan gestures. Almost identical
+ * API to normal `Animated.Value`, but multiplexed. Contains two regular
+ * `Animated.Value`s under the hood. Example:
+ *
+ *```javascript
+ * class DraggableView extends React.Component {
+ * constructor(props) {
+ * super(props);
+ * this.state = {
+ * pan: new Animated.ValueXY(), // inits to zero
+ * };
+ * this.state.panResponder = PanResponder.create({
+ * onStartShouldSetPanResponder: () => true,
+ * onPanResponderMove: Animated.event([null, {
+ * dx: this.state.pan.x, // x,y are Animated.Value
+ * dy: this.state.pan.y,
+ * }]),
+ * onPanResponderRelease: () => {
+ * Animated.spring(
+ * this.state.pan, // Auto-multiplexed
+ * {toValue: {x: 0, y: 0}} // Back to zero
+ * ).start();
+ * },
+ * });
+ * }
+ * render() {
+ * return (
+ *
+ * {this.props.children}
+ *
+ * );
+ * }
+ * }
+ *```
+ */
class AnimatedValueXY extends AnimatedWithChildren {
x: AnimatedValue;
y: AnimatedValue;
@@ -677,6 +759,13 @@ class AnimatedValueXY extends AnimatedWithChildren {
delete this._listeners[id];
}
+ /**
+ * Converts `{x, y}` into `{left, top}` for use in style, e.g.
+ *
+ *```javascript
+ * style={this.state.anim.getLayout()}
+ *```
+ */
getLayout(): {[key: string]: AnimatedValue} {
return {
left: this.x,
@@ -684,6 +773,15 @@ class AnimatedValueXY extends AnimatedWithChildren {
};
}
+ /**
+ * Converts `{x, y}` into a useable translation transform, e.g.
+ *
+ *```javascript
+ * style={{
+ * transform: this.state.anim.getTranslateTransform()
+ * }}
+ *```
+ */
getTranslateTransform(): Array<{[key: string]: AnimatedValue}> {
return [
{translateX: this.x},
@@ -1235,21 +1333,6 @@ var stagger = function(
type Mapping = {[key: string]: Mapping} | AnimatedValue;
-/**
- * Takes an array of mappings and extracts values from each arg accordingly,
- * then calls setValue on the mapped outputs. e.g.
- *
- * onScroll={this.AnimatedEvent(
- * [{nativeEvent: {contentOffset: {x: this._scrollX}}}]
- * {listener} // optional listener invoked asynchronously
- * )
- * ...
- * onPanResponderMove: this.AnimatedEvent([
- * null, // raw event arg
- * {dx: this._panX}, // gestureState arg
- * ]),
- *
- */
type EventConfig = {listener?: ?Function};
var event = function(
argMapping: Array,
@@ -1287,23 +1370,179 @@ var event = function(
};
};
+/**
+ * Animations are an important part of modern UX, and the `Animated`
+ * library is designed to make them fluid, powerful, and easy to build and
+ * maintain.
+ *
+ * The simplest workflow is to create an `Animated.Value`, hook it up to one or
+ * more style attributes of an animated component, and then drive updates either
+ * via animations, such as `Animated.timing`, or by hooking into gestures like
+ * panning or scolling via `Animated.event`. `Animated.Value` can also bind to
+ * props other than style, and can be interpolated as well. Here is a basic
+ * example of a container view that will fade in when it's mounted:
+ *
+ *```javascript
+ * class FadeInView extends React.Component {
+ * constructor(props) {
+ * super(props);
+ * this.state = {
+ * fadeAnim: new Animated.Value(0), // init opacity 0
+ * };
+ * }
+ * componentDidMount() {
+ * Animated.timing( // Uses easing functions
+ * this.state.fadeAnim, // The value to drive
+ * {toValue: 1}, // Configuration
+ * ).start(); // Don't forget start!
+ * }
+ * render() {
+ * return (
+ * // Binds
+ * {this.props.children}
+ *
+ * );
+ * }
+ * }
+ *```
+ *
+ * Note that only animatable components can be animated. `View`, `Text`, and
+ * `Image` are already provided, and you can create custom ones with
+ * `createAnimatedComponent`. These special components do the magic of binding
+ * the animated values to the properties, and do targetted native updates to
+ * avoid the cost of the react render and reconciliation process on every frame.
+ * They also handle cleanup on unmount so they are safe by default.
+ *
+ * Animations are heavily configurable. Custom and pre-defined easing
+ * functions, delays, durations, decay factors, spring constants, and more can
+ * all be tweaked depending on the type of animation.
+ *
+ * A single `Animated.Value` can drive any number of properties, and each
+ * property can be run through an interpolation first. An interpolation maps
+ * input ranges to output ranges, typically using a linear interpolation but
+ * also supports easing functions. By default, it will extrapolate the curve
+ * beyond the ranges given, but you can also have it clamp the output value.
+ *
+ * For example, you may want to think about your `Animated.Value` as going from
+ * 0 to 1, but animate the position from 150px to 0px and the opacity from 0 to
+ * 1. This can easily be done by modifying `style` in the example above like so:
+ *
+ *```javascript
+ * style={{
+ * opacity: this.state.fadeAnim, // Binds directly
+ * transform: [{
+ * translateY: this.state.fadeAnim.interpolate({
+ * inputRange: [0, 1],
+ * outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
+ * }),
+ * }],
+ * }}>
+ *```
+ *
+ * Animations can also be combined in complex ways using composition functions
+ * such as `sequence` and `parallel`, and can also be chained together simply
+ * by setting the `toValue` of one animation to be another `Animated.Value`.
+ *
+ * `Animated.ValueXY` is handy for 2D animations, like panning, and there are
+ * other helpful additions like `setOffset` and `getLayout` to aid with typical
+ * interaction patterns, like drag-and-drop.
+ *
+ * You can see more example usage in `AnimationExample.js`, the Gratuitous
+ * Animation App, and [Animations documentation guide](http://facebook.github.io/react-native/docs/animations.html).
+ *
+ * Note that `Animated` is designed to be fully serializable so that animations
+ * can be run in a high performace way, independent of the normal JavaScript
+ * event loop. This does influence the API, so keep that in mind when it seems a
+ * little trickier to do something compared to a fully synchronous system.
+ * Checkout `Animated.Value.addListener` as a way to work around some of these
+ * limitations, but use it sparingly since it might have performance
+ * implications in the future.
+ */
module.exports = {
- delay,
- sequence,
- parallel,
- stagger,
+ /**
+ * Standard value class for driving animations. Typically initialized with
+ * `new Animated.Value(0);`
+ */
+ Value: AnimatedValue,
+ /**
+ * 2D value class for driving 2D animations, such as pan gestures.
+ */
+ ValueXY: AnimatedValueXY,
+ /**
+ * An animatable View component.
+ */
+ View: createAnimatedComponent(View),
+ /**
+ * An animatable Text component.
+ */
+ Text: createAnimatedComponent(Text),
+ /**
+ * An animatable Image component.
+ */
+ Image: createAnimatedComponent(Image),
+
+ /**
+ * Animates a value from an initial velocity to zero based on a decay
+ * coefficient.
+ */
decay,
+ /**
+ * Animates a value along a timed easing curve. The `Easing` module has tons
+ * of pre-defined curves, or you can use your own function.
+ */
timing,
+ /**
+ * Spring animation based on Rebound and Origami. Tracks velocity state to
+ * create fluid motions as the `toValue` updates, and can be chained together.
+ */
spring,
+ /**
+ * Starts an animation after the given delay.
+ */
+ delay,
+ /**
+ * Starts an array of animations in order, waiting for each to complete
+ * before starting the next. If the current running animation is stopped, no
+ * following animations will be started.
+ */
+ sequence,
+ /**
+ * Starts an array of animations all at the same time. By default, if one
+ * of the animations is stopped, they will all be stopped. You can override
+ * this with the `stopTogether` flag.
+ */
+ parallel,
+ /**
+ * Array of animations may run in parallel (overlap), but are started in
+ * sequence with successive delays. Nice for doing trailing effects.
+ */
+ stagger,
+
+ /**
+ * Takes an array of mappings and extracts values from each arg accordingly,
+ * then calls `setValue` on the mapped outputs. e.g.
+ *
+ *```javascript
+ * onScroll={this.AnimatedEvent(
+ * [{nativeEvent: {contentOffset: {x: this._scrollX}}}]
+ * {listener}, // Optional async listener
+ * )
+ * ...
+ * onPanResponderMove: this.AnimatedEvent([
+ * null, // raw event arg ignored
+ * {dx: this._panX}, // gestureState arg
+ * ]),
+ *```
+ */
event,
- Value: AnimatedValue,
- ValueXY: AnimatedValueXY,
- __PropsOnlyForTests: AnimatedProps,
- View: createAnimatedComponent(View),
- Text: createAnimatedComponent(Text),
- Image: createAnimatedComponent(Image),
+ /**
+ * Make any React component Animatable. Used to create `Animated.View`, etc.
+ */
createAnimatedComponent,
+
+ __PropsOnlyForTests: AnimatedProps,
};