Javascript示例的语法分析请见:Javascript for React Native语法教程 - GUIDE|Animations
虽然英文一般,但学习新知识的时候还是习惯于直接啃英文文档,理由无他,有些中文翻译实在是太烂了,而且即使翻译水平尚可也有很多知识点描述的没有英文原生文档那么准确。因此在这里只做注释性的讲解,力求对英文文档的理解更容易但是不干扰其内容。因此在文末会提供英文文档阅读时我比较陌生的词,希望也能给你帮助。
React Native的动画API分为两个系统:
LayoutAnimation
:强力的,用于全局可控的动画效果;Animated
:用于对视图做更细粒度的交互控制,比如缩放、弹跳这种动画。
一个例子
一个完整的在mount时具有弹簧效果动画(spring bounce)的组件例子如下:
class Playground extends React.Component {
constructor(props: any) {
super(props)
this.state = {
bounceValue: new Animated.Value(0),
};
}
render(): ReactElement {
return (
<Animated.Image
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
style={{
flex: 1,
transform: [
{scale: this.state.bounceValue},
]
}}
/>
);
}
componentDidMount() {
this.state.bounceValue.setValue(1.5);
Animated.spring(
this.state.bounceValue,
{
toValue: 0.8,
friction: 1,
}
).start();
}
}
组件在mount时以bounceValue(1.5)的比例为初始值做spring bounce动画。
这样做比调用setState
再re-rendering效率要高。
后续可以放到异步线程中。
核心API
两种值类型:Value、ValueXY for vector
三种动画类型:spring(弹簧)、decay(衰变)、timing
三种支持动画的原生组件:View, Text, Image。同时你可以通过继承Animated.createAnimatedComponent
创建自己的组件。
spring
:简单的弹簧物理效果。参见:Origamifriction
:弹力/过度,默认值为7tension
:速度。默认为40decay
:带有初始速度并逐渐减弱到停止。velocity
:初始速率,必须指定初始值。deceleration
:衰退的速率。默认是0.997timing
:映射时间范围减小值。duration
:动画时间长度。默认为500(ms)easing
:ease效果,默认值 Easing.inOut(Easing.ease)delay
:动画开始前的延迟时间,默认为0(ms)
组合动画
React Native的动画可以通过四种方式组合起来:平行(parallel)、顺序(sequence)、错开(stagger)、延时(delay)。
使用的方式也非常简单,向对应名字的方法传入一个动画的数组,然后调用start/stop
方法即可。并且组合方式也可以互相嵌套。比如:
Animated.sequence([
Animated.decay(position, {
velocity: {x: gestureState.vx, y:gestureState.vy},
deceleration: 0.997,
}),
Animated.parallel([
Animated.spring(position, {
toValue: {x: 0, y: 0}
}),
Animated.timing(twirl, {
toValue: 360,
}),
]),
]).start();
动画停止:默认的,如果组合中的任一个动画停止或者被打断,其他动画也会随着一起停止。parallel
组合方式下提供了一个stopTogether
的选项,可以通过设置它为false
来取消这样的行为。
更多关于动画的知识
Animated是一个正在开发中、非常强大的Library,涉及到知识非常多,我会持续更新这篇文章。
- Interpolation(插值)
- Input Output
- Tracking Dynamic Values
- Input Events
- Responding to the Current Animation Value
- Future Work
LayoutAnimation
LayoutAnimation只在iOS平台才有。
LayoutAnimation用于全局控制动画的创建和更新。在当前视图动画会影响到父视图时会非常好用。典型的例子比如一个查看更多
按钮,点击之后会影响父视图的大小,同时将下方的行元素都推下去。
尽管LayoutAnimation非常强大,非常好用,但是不一定满足所有的需求。如果你需要的效果不在LayoutAnimation提供的范围内,请移步Animated或者其他动画库。
看一下官方给的示例图:
示例代码:
var App = React.createClass({
componentWillMount() {
// Animate creation
LayoutAnimation.spring();
},
getInitialState() {
return {w: 100, h:100 }
},
_onPress() {
// Animate the update
LayoutAnimation.spring();
this.setState({w: this.state.w + 15, h: this.state.h + 15 });
},
render: function() {
return (
<View style={styles.container}>
<View style={[styles.box, {width: this.state.w, height: this.state.h}]} />
<TouchableOpacity onPress={this._onPress}>
<View style={styles.button}>
<Text style={styles.buttonText} >Press me!</Text>
</View>
</TouchableOpacity>
</View>
);
},
});
如果要了解更多可以查看 LayoutAnimation.js 的源码。
中间省略了几个Topic,后续慢慢补。
requestAnimationFrame
react-tween-state (Not recommended - use Animated instead)
Rebound (Not recommended - use Animated instead)
下面这个Topic比较重要,涉及到导航器的切换
Navigator Scene Transitions
右滑返回的代码示例:
var SCREEN_WIDTH = require('Dimensions').get('window').width;
var BaseConfig = Navigator.SceneConfigs.FloatFromRight;
var CustomLeftToRightGesture = Object.assign({}, BaseConfig.gestures.pop, {
// 取消pop时的回弹速率
snapVelocity: 8,
// 支持拖动的边缘宽度,这里设置为屏幕宽度,所以整个视图都支持拖动
edgeHitWidth: SCREEN_WIDTH,
});
var CustomSceneConfig = Object.assign({}, BaseConfig, {
// A very tightly wound spring will make this transition fast<!--?-->
springTension: 100,
springFriction: 1,
// 使用上面定义的gesture
gestures: {
pop: CustomLeftToRightGesutre,
}
});
上述代码是右滑返回的实现代码,在实际使用这个手势时时我们可以这样写。
顺便提一下,React Native提供的这个模拟器也是非常赞!
Words
- friction - 摩擦;摩擦力;
- optimize - 优化
- velocity - 速度
- gradually - 逐渐地
- ease - 缓解、减轻、容易;译为擦除?
- curve - 曲线
- twirl - 旋转的东西
- flexible - 有弹性的,灵活的
- comparison - 对比,比较
- dimension - 尺寸