React实战-深入分析ReactNative中的动画效果
React实战-深入分析ReactNative中的动画效果
说起动画效果感觉回到JavaScript的起源了,在早期的Web开发中,JS更多的是扮演着页面特效的角色,当然也只是属于做些边角料的工作,真正需要动画的地方,大多还是采用Flash或者Applet,Js更多的是操作html元素的变化,如果大量采用Js,则会严重影响页面的性能。
在了解ReactNative中动画之前,我们还是看看网页动画基本实现方式。在Web业务效果方面,基本的做法是改变Html页面元素的属性,例如:width,left,top等,导致页面重绘,由于元素属性变化和重绘过程存在时差,也就产生了动画的效果,但总的来说性能并不太好。在Css3中增加了transform和transition使得Web元素动画效果变的简单、流畅,再加上Html的canvas元素对视频的支持,大大降低了Web页面对插件式动画的依赖。在ReactNative的动画主要关注在Web元素的效果变化,视频的支持依然交给了canvas(weixin号:React实战)。
1.ReactNative中的四种变化方式
在ReactNative中实现动画效果的基本原理与之前并没有什么区别,再结合ReactJS的UI重绘原则,主要有以下方式:
a通过Js直接构造新的元素,改变Style属性。
if(this.state.complete === true){
return <View style=\{ \{width:20,height:20,backgroundColor:'red'\}\} />
\}else\{
return <View style=\{ \{width:20,height:20,backgroundColor:'blue'\}\} />
\}
b依据不同条件,设置不同的Style属性
d.采用Animator与transform相结合,实现更炫动画效果
以上四种方式,如果不需要产生变化效果,一般采用第二种,如果需要产生平滑的变化效果,推荐采用第四种。
到目前为止,动画依然是ReactNative的弱项,还在不断的发展中。主要的方式是采用LayoutAnimation和Animated来实现,但背后的原理依然是改变state中的值,引起UI重绘。LayoutAnimation主要用于整体布局的变化,Animated则用与更多规则和变化的特殊值变化。
2.ReactNative中Animated实现方式
Animated主要对两类特殊值的变化,一是单个值:Value,一个是对值对象值:ValueXY。
a.Animated.Value的单值实现方式
在state中定义Animated.Value的值:
this.state = {
bounceValue: new Animated.Value(0),
};
在页面属性中定义style属性,属性值基于state中的值:
触发动画效果:
Animated.spring(
this.state.bounceValue,
\{
toValue: 0.8,
friction: 1,
\}
).start();
b.Animator.ValueXY的双值实现方式:
在state中定义ValueXY值:
this.state = {
pan: new Animated.ValueXY(),
\};
定义指定元素拖动时的ValueXY变化:
this.state.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: Animated.event(\[null, \{
dx: this.state.pan.x,
dy: this.state.pan.y,
\}\]),
onPanResponderRelease: () => \{
Animated.spring(
this.state.pan,
\{toValue: \{x: 0, y: 0\}\}
).start();
\},
\});
设定特定元素的样式:
\{this.props.children\}
</Animated.View>
c.Animator设置过程中的约束
Animator在设置原理并不复杂,但是有一些潜规则,在缺乏文档的情况下,还是看看源码比较好。Animator设置过程中有以下约束:
1)Animator.Value的值虽然定义在state中,但是在页面元素中只有
module.exports = {
…AnimatedImplementation,
View: AnimatedImplementation.createAnimatedComponent(View),
Text: AnimatedImplementation.createAnimatedComponent(Text),
Image: AnimatedImplementation.createAnimatedComponent(Image),
ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView),
};
2)Animator.ValueXY的值{x,y}是特定的,如果你需要取值也应采用{x,y}
pan: new Animated.ValueXY()….
{dx: this.state.pan.x,dy: this.state.pan.y}
3.ReactNative中LayoutAnimation实现方式
在ReactNative中更简单的方式是对全局进行Animation设置,即采用LayoutAnimation,则一般的元素也可以访问state中的值,值的设置也就没有什么特殊的要求了,但是设置过程有些需要特别注意。其中在Android的控件里特别需要的是要加入原生组件,否则效果失效。如下:
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
动画启动也简单:
LayoutAnimation.spring();
4.组合动画
在设置动画效果时,我们往往并不止一个动画效果,可能是多个动画的组合,ReactNative为我们提供了Animated.sequence和Animated.parallel两个方法进行动画组合,使用也很简单:
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();
5.三种主要动画效果
在ReactNative中主要有三种动画效果:Spring, decay,timing,至于用法基本上看看参数就行,但是文档里给出的参数太少,还是看看源码知道这些动画的参数,以下是spring的参数表,其他的也可参加相关源码:
type SpringAnimationConfig = AnimationConfig & {
toValue: number | AnimatedValue | {x: number, y: number} | AnimatedValueXY,
overshootClamping?: bool,
restDisplacementThreshold?: number,
restSpeedThreshold?: number,
velocity?: number | {x: number, y: number},
bounciness?: number,
speed?: number,
tension?: number,
friction?: number,
};
6.动画过程中值的变化
在动画执行过程中,采用Animator时,Animator相关元素能自动获得Animator中的值,但这些值是不透明的,在外部是无法获得中间值的,我们只能添加相关事件,在动画执行结束时设置回调函数,以执行动画之后的操作。
及时采用LayoutAnimation时,我们获得的也只是最终值。
另外在ReactNative中提供了一种插值区间的方法interpolate,在动画效果值变化过程中,会自动进行区间映射。如:
value.interpolate({
inputRange: [0, 1],
outputRange: [0, 100],
});
git@github.com:chenhuitian/ReactNative.gitzhong">如果值为0.5,则映射输出为50,值为0.3,则输出为30。
7.demo的源码
git@github.com:chenhuitian/ReactNative.git
还没有评论,来说两句吧...