React Native-启动动画两次,错误开始未定义

时间:2019-12-06 07:37:00

标签: react-native react-animated react-native-animatable

animation = new Animated.Value(0);

animationSequnce = Animated.sequence(
    [Animated.timing(this.animation, { toValue: 1 }),
      Animated.timing(this.animation, { toValue: 0, delay: 1000 }),
    ],
  );

startAnimation = () => {
  animationSequnce.start();
}

stopAnimation = () => {
  animationSequnce.stop();
}

我想多次启动animation sequence

我通过编写在按下按钮时调用startAnimation的代码进行了测试。 动画在第一次运行时运行。 在第一个动画完成后单击第二个按钮时 发生Cannot read property 'start' of undefined错误。

startAnimation = () => {
  Animated.sequence(
    [Animated.timing(this.animation, { toValue: 1 }),
      Animated.timing(this.animation, { toValue: 0, delay: 1000 }),
    ],
  ).start();
} 

对此startAnimation所做的更改不会导致错误,但是您将无法调用stopAnimation,因为它将每次都调用不同的AnimationSequnce

多次使用动画的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

停止动画

this.animation.stopAnimation()

可选动画停止播放时获取回叫

this.animation.stopAnimation(this.callback())

Animated.timing(
  this.animation
).stop();

答案 1 :(得分:0)

第一次调用 Animated.sequence() 时,react native 创建一个变量 current,引用当前执行动画的索引,并存储在本地。

Animated.sequence().start() 完成后,变量 current 不会被清除或重置为 0,因此您第二次在同一个序列动画上调用 start() 时,数组索引超出绑定并导致错误。

这是react native的一个隐藏bug,下面是Animated.sequence

的实现
const sequence = function(
  animations: Array<CompositeAnimation>,
): CompositeAnimation {
  let current = 0;
  return {
    start: function(callback?: ?EndCallback) {
      const onComplete = function(result) {
        if (!result.finished) {
          callback && callback(result);
          return;
        }

        current++;

        if (current === animations.length) {
          callback && callback(result);
          return;
        }

        animations[current].start(onComplete);
      };

      if (animations.length === 0) {
        callback && callback({finished: true});
      } else {
        animations[current].start(onComplete);
      }
    },

    stop: function() {
      if (current < animations.length) {
        animations[current].stop();
      }
    },

    reset: function() {
      animations.forEach((animation, idx) => {
        if (idx <= current) {
          animation.reset();
        }
      });
      current = 0;
    },

    _startNativeLoop: function() {
      throw new Error(
        'Loops run using the native driver cannot contain Animated.sequence animations',
      );
    },

    _isUsingNativeDriver: function(): boolean {
      return false;
    },
  };
};

我的解决方案是定义一个自定义序列,并在序列动画完成后手动将 current 重置为 0:

const sequence = function(
  animations: Array<CompositeAnimation>,
): CompositeAnimation {
  let current = 0;
  return {
    start: function(callback?: ?EndCallback) {
      const onComplete = function(result) {
        if (!result.finished) {
          current = 0;
          callback && callback(result);
          return;
        }

        current++;

        if (current === animations.length) {
          current = 0;
          callback && callback(result);
          return;
        }

        animations[current].start(onComplete);
      };

      if (animations.length === 0) {
        current = 0;
        callback && callback({finished: true});
      } else {
        animations[current].start(onComplete);
      }
    },

    stop: function() {
      if (current < animations.length) {
        animations[current].stop();
      }
    },

    reset: function() {
      animations.forEach((animation, idx) => {
        if (idx <= current) {
          animation.reset();
        }
      });
      current = 0;
    },

    _startNativeLoop: function() {
      throw new Error(
        'Loops run using the native driver cannot contain Animated.sequence animations',
      );
    },

    _isUsingNativeDriver: function(): boolean {
      return false;
    },
  };
};