From fdeb6a842a31ba6db42a1a4dc3ffe5cb8efc6c3e Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Thu, 3 Sep 2015 13:00:09 -0700 Subject: [PATCH] [RN] New AnimationExample --- Examples/UIExplorer/AnimatedExample.js | 230 ++++++++++++++++++ .../AnExApp.js | 0 .../AnExBobble.js | 0 .../AnExChained.js | 0 .../AnExScroll.js | 0 .../AnExSet.js | 0 .../AnExSlides.md | 0 .../AnExTilt.js | 0 Examples/UIExplorer/TimerExample.js | 41 +--- Examples/UIExplorer/UIExplorerButton.js | 56 +++++ Examples/UIExplorer/UIExplorerList.ios.js | 3 +- Libraries/Animated/Easing.js | 6 + 12 files changed, 301 insertions(+), 35 deletions(-) create mode 100644 Examples/UIExplorer/AnimatedExample.js rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExApp.js (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExBobble.js (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExChained.js (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExScroll.js (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExSet.js (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExSlides.md (100%) rename Examples/UIExplorer/{AnimationExample => AnimatedGratuitousApp}/AnExTilt.js (100%) create mode 100644 Examples/UIExplorer/UIExplorerButton.js 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 {