[RN] New AnimationExample

This commit is contained in:
Spencer Ahrens 2015-09-03 13:00:09 -07:00
parent 836e4c03fc
commit fdeb6a842a
12 changed files with 301 additions and 35 deletions

View File

@ -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 (
<Animated.View // Special animatable View
style={{
opacity: this.state.fadeAnim, // Binds
}}>
{this.props.children}
</Animated.View>
);
}
}
class FadeInExample extends React.Component {
constructor(props) {
super(props);
this.state = {
show: true,
};
}
render() {
return (
<View>
<UIExplorerButton onPress={() => {
this.setState((state) => (
{show: !state.show}
));
}}>
Press to {this.state.show ?
'Hide' : 'Show'}
</UIExplorerButton>
{this.state.show && <FadeInView>
<View style={styles.content}>
<Text>FadeInView</Text>
</View>
</FadeInView>}
</View>
);
}
}
return <FadeInExample />;
},
},
{
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 (
<View>
<UIExplorerButton onPress={() => {
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!
</UIExplorerButton>
<Animated.View
style={[styles.content, {
transform: [ // Array order matters
{scale: this.anim.interpolate({
inputRange: [0, 1],
outputRange: [1, 4],
})},
{translateX: this.anim.interpolate({
inputRange: [0, 1],
outputRange: [0, 500],
})},
{rotate: this.anim.interpolate({
inputRange: [0, 1],
outputRange: [
'0deg', '360deg' // 'deg' or 'rad'
],
})},
]}
]}>
<Text>Transforms!</Text>
</Animated.View>
</View>
);
},
},
{
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 (
<View>
<UIExplorerButton onPress={() => {
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
</UIExplorerButton>
{['Composite', 'Easing', 'Animations!'].map(
(text, ii) => (
<Animated.View
style={[styles.content, {
left: this.anims[ii]
}]}>
<Text>{text}</Text>
</Animated.View>
)
)}
</View>
);
},
},
{
title: 'Continuous Interactions',
description: 'Gesture events, chaining, 2D ' +
'values, interrupting and transitioning ' +
'animations, etc.',
render: () => (
<Text>Checkout the Gratuitous Animation App!</Text>
),
}
];
var styles = StyleSheet.create({
content: {
backgroundColor: 'deepskyblue',
borderWidth: 1,
borderColor: 'dodgerblue',
padding: 20,
margin: 20,
borderRadius: 10,
alignItems: 'center',
},
});

View File

@ -18,27 +18,12 @@
var React = require('react-native'); var React = require('react-native');
var { var {
AlertIOS, AlertIOS,
StyleSheet,
Text, Text,
TouchableHighlight, TouchableHighlight,
View, View,
} = React; } = React;
var TimerMixin = require('react-timer-mixin'); var TimerMixin = require('react-timer-mixin');
var UIExplorerButton = require('./UIExplorerButton');
var Button = React.createClass({
render: function() {
return (
<TouchableHighlight
onPress={this.props.onPress}
style={styles.button}
underlayColor="#eeeeee">
<Text>
{this.props.children}
</Text>
</TouchableHighlight>
);
},
});
var TimerTester = React.createClass({ var TimerTester = React.createClass({
mixins: [TimerMixin], mixins: [TimerMixin],
@ -52,9 +37,9 @@ var TimerTester = React.createClass({
render: function() { render: function() {
var args = 'fn' + (this.props.dt !== undefined ? ', ' + this.props.dt : ''); var args = 'fn' + (this.props.dt !== undefined ? ', ' + this.props.dt : '');
return ( return (
<Button onPress={this._run}> <UIExplorerButton onPress={this._run}>
Measure: {this.props.type}({args}) - {this._ii || 0} Measure: {this.props.type}({args}) - {this._ii || 0}
</Button> </UIExplorerButton>
); );
}, },
@ -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.framework = 'React';
exports.title = 'Timers, TimerMixin'; exports.title = 'Timers, TimerMixin';
exports.description = 'The TimerMixin provides timer functions for executing ' + exports.description = 'The TimerMixin provides timer functions for executing ' +
@ -183,9 +156,9 @@ exports.examples = [
if (this.state.showTimer) { if (this.state.showTimer) {
var timer = [ var timer = [
<TimerTester ref="interval" dt={25} type="setInterval" />, <TimerTester ref="interval" dt={25} type="setInterval" />,
<Button onPress={() => this.refs.interval.clear() }> <UIExplorerButton onPress={() => this.refs.interval.clear() }>
Clear interval Clear interval
</Button> </UIExplorerButton>
]; ];
var toggleText = 'Unmount timer'; var toggleText = 'Unmount timer';
} else { } else {
@ -195,9 +168,9 @@ exports.examples = [
return ( return (
<View> <View>
{timer} {timer}
<Button onPress={this._toggleTimer}> <UIExplorerButton onPress={this._toggleTimer}>
{toggleText} {toggleText}
</Button> </UIExplorerButton>
</View> </View>
); );
}, },

View File

@ -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 (
<TouchableHighlight
onPress={this.props.onPress}
style={styles.button}
underlayColor="grey">
<Text>
{this.props.children}
</Text>
</TouchableHighlight>
);
},
});
var styles = StyleSheet.create({
button: {
borderColor: 'dimgray',
borderRadius: 8,
borderWidth: 1,
padding: 10,
margin: 5,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'lightgrey',
},
});
module.exports = UIExplorerButton;

View File

@ -60,7 +60,8 @@ var APIS = [
require('./ActionSheetIOSExample'), require('./ActionSheetIOSExample'),
require('./AdSupportIOSExample'), require('./AdSupportIOSExample'),
require('./AlertIOSExample'), require('./AlertIOSExample'),
require('./AnimationExample/AnExApp'), require('./AnimatedExample'),
require('./AnimatedGratuitousApp/AnExApp'),
require('./AppStateIOSExample'), require('./AppStateIOSExample'),
require('./AsyncStorageExample'), require('./AsyncStorageExample'),
require('./BorderExample'), require('./BorderExample'),

View File

@ -123,12 +123,18 @@ class Easing {
return easing; return easing;
} }
/**
* Runs an easing function backwards.
*/
static out( static out(
easing: (t: number) => number, easing: (t: number) => number,
): (t: number) => number { ): (t: number) => number {
return (t) => 1 - easing(1 - t); return (t) => 1 - easing(1 - t);
} }
/**
* Makes any easing function symmetrical.
*/
static inOut( static inOut(
easing: (t: number) => number, easing: (t: number) => number,
): (t: number) => number { ): (t: number) => number {