在React Native中创建一个动画有多种方式。
使用react-native包的Animated组件创建动画 
使用react-native包的LayoutAnimation创建布局动画 
使用Web API标准的requestAnimationFrame控制动画 
 
以上是目前常用的几种在React Native中创建动画的方式,Animated动画可以进行nativeDriver加速,但是如果属性不支持,将会使用requestAnimationFrame实现计算。LayoutAnimation控制粒度不及Animated细。
本文主要来说说Animated.Value及Animated.ValueXY
 
使用Animated创建一个动画 先通过使用Animated创建一个动画回顾一下React Native中Animated的使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  AnimatedPlayground  extends  Component   {  state = {     size: new  Animated.Value(50 )    }   componentDidMount () {     Animated.timing(this .state.size, {       toValue: 200       }).start()    }   render () {     return  (       <Animated.View style={{         backgroundColor: '#000' ,         width: this .state.size,          height: this .state.size       }}/>     )   } } 
 
使用Animated做动画需要注意几个地方
元素需要变化的属性值必须用Animated.Value或者Animated.ValueXY初始化。 
需要进行动画的元素需要转换成Animated的组件,Animated提供了Animated.View、Animated.Text、Animated.Image和Animated.ScrollView ,其他组件通过Animated.createAnimatedComponent()方法处理后即可使用Animated.Value值作为属性 
调用Animated的方法创建一个动画对象常用的方法有Animated.decay、Animated.timing、Animated.spring等 
调用第三步生成对象的start()方法即可触发动画 
 
Animated.timing()方法 在Animated创建动画的方法中,timing是最简单易懂的一个,这里看一下timing方法内部都做了什么。
注意:文中的源码基于0.55.4版本的react-native源码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 const  timing = function (  value: AnimatedValue | AnimatedValueXY,   config: TimingAnimationConfig,  ): CompositeAnimation   {  const  start = function (     animatedValue: AnimatedValue | AnimatedValueXY,     configuration: TimingAnimationConfig,     callback?: ?EndCallback,    ): void   {    callback = _combineCallbacks(callback, configuration);     const  singleValue: any = animatedValue;     const  singleConfig: any = configuration;     singleValue.stopTracking();     if  (configuration.toValue instanceof  AnimatedNode) {       singleValue.track(         new  AnimatedTracking(           singleValue,           configuration.toValue,           TimingAnimation,           singleConfig,           callback,         ),       );     } else  {       singleValue.animate(new  TimingAnimation(singleConfig), callback);     }   };   return  (     maybeVectorAnim(value, config, timing) || {       start: function (callback?: ?EndCallback ): void   {         start(value, config, callback);       },       stop: function ( ): void   {         value.stopAnimation();       },       reset: function ( ): void   {         value.resetAnimation();       },       _startNativeLoop: function (iterations?: number ): void   {         const  singleConfig = {...config, iterations};         start(value, singleConfig);       },       _isUsingNativeDriver: function ( ): boolean   {         return  config.useNativeDriver || false ;       },     }   ); }; 
 
timing方法会返回一个对象,在返回前会尝试使用maybeVectorAnim进行坐标值的准换,如果值不是坐标值,将会返回一个对象。在上面的例子中,对timing返回的对象调用start()方法会开始动画,所以start方法是触发动画的关键。跟随代码可以找到最后会调用Animated.Value的animate方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 animate(animation: Animation, callback : ?EndCallback): void  {   let  handle = null ;   if  (animation.__isInteraction) {     handle = InteractionManager.createInteractionHandle();   }   const  previousAnimation = this ._animation;   this ._animation && this ._animation.stop();   this ._animation = animation;   animation.start(     this ._value,     value => {                     this ._updateValue(value, true  );     },     result => {       this ._animation = null ;       if  (handle !== null ) {         InteractionManager.clearInteractionHandle(handle);       }       callback && callback(result);     },     previousAnimation,     this ,   ); } 
 
这个方法通过调用传入的animation.start方法处理值更改,当值update时调用自身的_updateValue最后会调用到_flush,这个方法是一个关键方法,阅读以下它的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  _flush (rootNode: AnimatedValue ): void   {  const  animatedStyles = new  Set ();   function  findAnimatedStyles (node )  {          if  (typeof  node.update === 'function' ) {       animatedStyles.add(node);     } else  {       node.__getChildren().forEach(findAnimatedStyles);     }   }   findAnimatedStyles(rootNode);      animatedStyles.forEach(animatedStyle  =>  animatedStyle.update()); } 
 
它会遍历所有子节点,找出带有update方法的节点,并调用他们的update方法。好了,Animated.Value的代码阅读展示到这里,接下来看看createAnimatedComponent这个方法主要做了什么。
createAnimatedComponent 高阶组件 打开它的源码可以看到它是一个高阶组件,它返回的组件中有一个_propsAnimated的变量,在UNSAFE_componentWillMount中调用_attachProps进行初始化,传入了props和一个函数_animatedPropsCallback,这个传入函数的作用是通过setNativeProps更新最终的Component。来看一下AnimatedProps的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  AnimatedProps  extends  AnimatedNode   {true... true__attach(): void  {     for  (const  key in  this ._props) {       const  value = this ._props[key];       if  (value instanceof  AnimatedNode) {         value.__addChild(this );       }     }   }   ...   update(): void  {     this ._callback();   } } 
 
里面的update方法将会调用传入的回调,回到上面说的_flush方法,可以大概知道了Animated的原理了。但是这里还有一个问题就是什么时候将Value和组件关联起来的,就是为什么_flush能找到AnimatedProps的update方法。 上面代码中我贴出了__attach方法,改方法会在初始化的时候调用,最终会把this传入value.__addChild,这里的value就是通过props传入的Animated.Value。在_flush中会调用node.__getChildren().forEach(findAnimatedStyles);,它将会返回在前面添加的Child。
到这里就能理解在React Native的Animated动画实现流程了。
文章只是简单分析了一下部分源码,并没有完全分析,源码中还有很多优化及功能代码,比如detach、事件通知等。