diff --git a/Examples/UIExplorer/AnimatedExample.js b/Examples/UIExplorer/AnimatedExample.js
new file mode 100644
index 000000000..e417cacbe
--- /dev/null
+++ b/Examples/UIExplorer/AnimatedExample.js
@@ -0,0 +1,230 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+ Animated,
+ Easing,
+ StyleSheet,
+ Text,
+ View,
+} = React;
+var UIExplorerButton = require('./UIExplorerButton');
+
+exports.framework = 'React';
+exports.title = 'Animated - Examples';
+exports.description = 'Animated provides a powerful ' +
+ 'and easy-to-use API for building modern, ' +
+ 'interactive user experiences.';
+
+exports.examples = [
+ {
+ title: 'FadeInView',
+ description: 'Uses a simple timing animation to ' +
+ 'bring opacity from 0 to 1 when the component ' +
+ 'mounts.',
+ render: function() {
+ class FadeInView extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ fadeAnim: new Animated.Value(0), // opacity 0
+ };
+ }
+ componentDidMount() {
+ Animated.timing( // Uses easing functions
+ this.state.fadeAnim, // The value to drive
+ {
+ toValue: 1, // Target
+ duration: 2000, // Configuration
+ },
+ ).start(); // Don't forget start!
+ }
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ }
+ class FadeInExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ show: true,
+ };
+ }
+ render() {
+ return (
+
+ {
+ this.setState((state) => (
+ {show: !state.show}
+ ));
+ }}>
+ Press to {this.state.show ?
+ 'Hide' : 'Show'}
+
+ {this.state.show &&
+
+ FadeInView
+
+ }
+
+ );
+ }
+ }
+ return ;
+ },
+ },
+ {
+ title: 'Transform Bounce',
+ description: 'One `Animated.Value` is driven by a ' +
+ 'spring with custom constants and mapped to an ' +
+ 'ordered set of transforms. Each transform has ' +
+ 'an interpolation to convert the value into the ' +
+ 'right range and units.',
+ render: function() {
+ this.anim = this.anim || new Animated.Value(0);
+ return (
+
+ {
+ Animated.spring(this.anim, {
+ toValue: 0, // Returns to the start
+ velocity: 3, // Velocity makes it move
+ tension: -10, // Slow
+ friction: 1, // Oscillate a lot
+ }).start(); }}>
+ Press to Fling it!
+
+
+ Transforms!
+
+
+ );
+ },
+ },
+ {
+ title: 'Composite Animations with Easing',
+ description: 'Sequence, parallel, delay, and ' +
+ 'stagger with different easing functions.',
+ render: function() {
+ this.anims = this.anims || [1,2,3].map(
+ () => new Animated.Value(0)
+ );
+ return (
+
+ {
+ var timing = Animated.timing;
+ Animated.sequence([ // One after the other
+ timing(this.anims[0], {
+ toValue: 200,
+ easing: Easing.linear,
+ }),
+ Animated.delay(400), // Use with sequence
+ timing(this.anims[0], {
+ toValue: 0,
+ easing: Easing.elastic(2), // Springy
+ }),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(
+ anim, {toValue: 200}
+ )).concat(
+ this.anims.map((anim) => timing(
+ anim, {toValue: 0}
+ ))),
+ ),
+ Animated.delay(400),
+ Animated.parallel([
+ Easing.inOut(Easing.quad), // Symmetric
+ Easing.back(1.5), // Goes backwards first
+ Easing.ease // Default bezier
+ ].map((easing, ii) => (
+ timing(this.anims[ii], {
+ toValue: 320, easing, duration: 3000,
+ })
+ ))),
+ Animated.delay(400),
+ Animated.stagger(200,
+ this.anims.map((anim) => timing(anim, {
+ toValue: 0,
+ easing: Easing.bounce, // Like a ball
+ duration: 2000,
+ })),
+ ),
+ ]).start(); }}>
+ Press to Animate
+
+ {['Composite', 'Easing', 'Animations!'].map(
+ (text, ii) => (
+
+ {text}
+
+ )
+ )}
+
+ );
+ },
+ },
+ {
+ title: 'Continuous Interactions',
+ description: 'Gesture events, chaining, 2D ' +
+ 'values, interrupting and transitioning ' +
+ 'animations, etc.',
+ render: () => (
+ Checkout the Gratuitous Animation App!
+ ),
+ }
+];
+
+var styles = StyleSheet.create({
+ content: {
+ backgroundColor: 'deepskyblue',
+ borderWidth: 1,
+ borderColor: 'dodgerblue',
+ padding: 20,
+ margin: 20,
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+});
diff --git a/Examples/UIExplorer/AnimationExample/AnExApp.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExApp.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js
diff --git a/Examples/UIExplorer/AnimationExample/AnExBobble.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExBobble.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
diff --git a/Examples/UIExplorer/AnimationExample/AnExChained.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExChained.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
diff --git a/Examples/UIExplorer/AnimationExample/AnExScroll.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExScroll.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js
diff --git a/Examples/UIExplorer/AnimationExample/AnExSet.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExSet.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js
diff --git a/Examples/UIExplorer/AnimationExample/AnExSlides.md b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSlides.md
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExSlides.md
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExSlides.md
diff --git a/Examples/UIExplorer/AnimationExample/AnExTilt.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js
similarity index 100%
rename from Examples/UIExplorer/AnimationExample/AnExTilt.js
rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js
diff --git a/Examples/UIExplorer/TimerExample.js b/Examples/UIExplorer/TimerExample.js
index b5923b350..8ef94cafe 100644
--- a/Examples/UIExplorer/TimerExample.js
+++ b/Examples/UIExplorer/TimerExample.js
@@ -18,27 +18,12 @@
var React = require('react-native');
var {
AlertIOS,
- StyleSheet,
Text,
TouchableHighlight,
View,
} = React;
var TimerMixin = require('react-timer-mixin');
-
-var Button = React.createClass({
- render: function() {
- return (
-
-
- {this.props.children}
-
-
- );
- },
-});
+var UIExplorerButton = require('./UIExplorerButton');
var TimerTester = React.createClass({
mixins: [TimerMixin],
@@ -52,9 +37,9 @@ var TimerTester = React.createClass({
render: function() {
var args = 'fn' + (this.props.dt !== undefined ? ', ' + this.props.dt : '');
return (
-
+
);
},
@@ -112,18 +97,6 @@ var TimerTester = React.createClass({
},
});
-var styles = StyleSheet.create({
- button: {
- borderColor: 'gray',
- borderRadius: 8,
- borderWidth: 1,
- padding: 10,
- margin: 5,
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
-
exports.framework = 'React';
exports.title = 'Timers, TimerMixin';
exports.description = 'The TimerMixin provides timer functions for executing ' +
@@ -183,9 +156,9 @@ exports.examples = [
if (this.state.showTimer) {
var timer = [
,
-
+
];
var toggleText = 'Unmount timer';
} else {
@@ -195,9 +168,9 @@ exports.examples = [
return (
{timer}
-
+
);
},
diff --git a/Examples/UIExplorer/UIExplorerButton.js b/Examples/UIExplorer/UIExplorerButton.js
new file mode 100644
index 000000000..082fe86ba
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerButton.js
@@ -0,0 +1,56 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ TouchableHighlight,
+} = React;
+
+var UIExplorerButton = React.createClass({
+ propTypes: {
+ onPress: React.PropTypes.func,
+ },
+ render: function() {
+ return (
+
+
+ {this.props.children}
+
+
+ );
+ },
+});
+
+var styles = StyleSheet.create({
+ button: {
+ borderColor: 'dimgray',
+ borderRadius: 8,
+ borderWidth: 1,
+ padding: 10,
+ margin: 5,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'lightgrey',
+ },
+});
+
+module.exports = UIExplorerButton;
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index d45f4ab70..436982dfe 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -60,7 +60,8 @@ var APIS = [
require('./ActionSheetIOSExample'),
require('./AdSupportIOSExample'),
require('./AlertIOSExample'),
- require('./AnimationExample/AnExApp'),
+ require('./AnimatedExample'),
+ require('./AnimatedGratuitousApp/AnExApp'),
require('./AppStateIOSExample'),
require('./AsyncStorageExample'),
require('./BorderExample'),
diff --git a/Libraries/Animated/Easing.js b/Libraries/Animated/Easing.js
index fe40b20b2..0b7b9099d 100644
--- a/Libraries/Animated/Easing.js
+++ b/Libraries/Animated/Easing.js
@@ -123,12 +123,18 @@ class Easing {
return easing;
}
+ /**
+ * Runs an easing function backwards.
+ */
static out(
easing: (t: number) => number,
): (t: number) => number {
return (t) => 1 - easing(1 - t);
}
+ /**
+ * Makes any easing function symmetrical.
+ */
static inOut(
easing: (t: number) => number,
): (t: number) => number {