reactnative 动画实现

来源:互联网 发布:知乎招聘 编辑:程序博客网 时间:2024/06/07 21:26

先看一个示例

class Playground extends React.Component {  constructor(props) {    super(props);    this.state = {      bounceValue: new Animated.Value(0),    };  }  render() {    return (      <Animated.Image                         // Base: Image, Text, View        source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}        style={{          flex: 1,          transform: [                        // `transform` is an ordered array            {scale: this.state.bounceValue},  // Map `bounceValue` to `scale`          ]        }}      />    );  }  componentDidMount() {    this.state.bounceValue.setValue(1.5);     // Start large    Animated.spring(                          // Base: spring, decay, timing      this.state.bounceValue,                 // Animate `bounceValue`      {        toValue: 0.8,                         // Animate to smaller size        friction: 1,                          // Bouncier spring      }    ).start();                                // Start the animation  }}

动画是从 Animated.spring开始的

找到对应实现

var spring = function(  value: AnimatedValue | AnimatedValueXY,  config: SpringAnimationConfig,): CompositeAnimation {  return maybeVectorAnim(value, config, spring) || {    start: function(callback?: ?EndCallback): void {      callback = _combineCallbacks(callback, config);      var singleValue: any = value;      var singleConfig: any = config;      singleValue.stopTracking();      if (config.toValue instanceof Animated) {        singleValue.track(new AnimatedTracking(          singleValue,          config.toValue,          SpringAnimation,          singleConfig,          callback        ));      } else {        singleValue.animate(new SpringAnimation(singleConfig), callback);      }    },    stop: function(): void {      value.stopAnimation();    },  };};

看来目标值存在singleValue,然后结束值和动画实现放在singleConfig

这里start函数都直接有的
最重要的是singleValue.animate(new SpringAnimation(singleConfig), callback);

singlevalue是一个Animated.Value 类型。调用这里面的animate方法。然后传入的类型是SpringAnimation。

Animated.Value

下面研究Animated.Value类型(这个类型我找不到) 但是从函数定义上来来说 是AnimatedValue类型

下面是value 的实现

  animate(animation: Animation, callback: ?EndCallback): void {    var handle = null;    if (animation.__isInteraction) {      handle = InteractionManager.createInteractionHandle();    }    var previousAnimation = this._animation;    this._animation && this._animation.stop();    this._animation = animation;    animation.start(      this._value,      (value) => {        // Natively driven animations will never call into that callback, therefore we can always        // pass flush = true to allow the updated value to propagate to native with setNativeProps        this._updateValue(value, true /* flush */);      },      (result) => {        this._animation = null;        if (handle !== null) {          InteractionManager.clearInteractionHandle(handle);        }        callback && callback(result);      },      previousAnimation,      this    );  }

看来是调用
SpringAnimation的start方法给了一个初始值 然后穿了两个函数。
主要是的是把_updateValue 也传了进去。

先把_updateValue放在这里。

 _updateValue(value: number, flush: bool): void {    this._value = value;    if (flush) {      _flush(this);    }    for (var key in this._listeners) {      this._listeners[key]({value: this.__getValue()});    }  }

class SpringAnimation extends Animation

SpringAnimation 在构造的时候就知道动画结束值和动画的持续时间

 constructor(    config: SpringAnimationConfigSingle,  ) {    super();    this._overshootClamping = withDefault(config.overshootClamping, false);    this._restDisplacementThreshold = withDefault(config.restDisplacementThreshold, 0.001);    this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.001);    this._initialVelocity = config.velocity;    this._lastVelocity = withDefault(config.velocity, 0);    this._toValue = config.toValue;    this._useNativeDriver = shouldUseNativeDriver(config);    this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;

结束值在this._toValue里面

start函数

  start(    fromValue: number,    onUpdate: (value: number) => void,    onEnd: ?EndCallback,    previousAnimation: ?Animation,    animatedValue: AnimatedValue  ): void {    this.__active = true;    this._startPosition = fromValue;    this._lastPosition = this._startPosition;    this._onUpdate = onUpdate;    this.__onEnd = onEnd;    this._lastTime = Date.now();    if (previousAnimation instanceof SpringAnimation) {      var internalState = previousAnimation.getInternalState();      this._lastPosition = internalState.lastPosition;      this._lastVelocity = internalState.lastVelocity;      this._lastTime = internalState.lastTime;    }    if (this._initialVelocity !== undefined &&        this._initialVelocity !== null) {      this._lastVelocity = this._initialVelocity;    }    if (this._useNativeDriver) {      this.__startNativeAnimation(animatedValue);    } else {      this.onUpdate();    }  }

start里面有个重点

 if (this._useNativeDriver) {      this.__startNativeAnimation(animatedValue);    } else {      this.onUpdate();      }

非native

这里会区分是本地动画还是自己的动画。
先分析onUpdate
opUpdate会计算出当前时间动画的值
然后调用this._onUpdate
这个就是AnimatedValue传进来的回调函数。执行的是AnimatedValue的 this._updateValue(value, true /* flush */);
这个函数会大flush标记 和 通知监听者 todo

看来SpringAnimation只是用于计算动画的当前的值。并没有涉及到原理性的东西。

native

下面看一下native的实现
__startNativeAnimation

__startNativeAnimation(animatedValue: AnimatedValue): void {    animatedValue.__makeNative();    this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();    NativeAnimatedAPI.startAnimatingNode(      this.__nativeId,      animatedValue.__getNativeTag(),      this.__getNativeAnimationConfig(),      this.__debouncedOnEnd.bind(this)    );  }

现在要去看NativeAnimatedHelper.js

下面就是要做分平台处理了
ios RCTNativeAnimatedModule.m
Android NativeAnimatedModule.java

RCTNativeAnimatedModule.m

这个类对外提供接口
RCT_EXPORT_METHOD(startAnimatingNode:(nonnull NSNumber *)animationId
nodeTag:(nonnull NSNumber *)nodeTag
config:(NSDictionary

0 0