在React Native中将旋转动画设置为最接近的值

时间:2019-03-17 02:36:20

标签: react-native

给出插值,必须旋转汽车标记:

for – else

以下GIF表示以下轴承:

answers = []
passed = False
while not passed:
    for question in questions:
        answer = input('Enter your answer')
        if (not is_valid_answer(answer)):
            # Start over.
            answers = []
            break
        answers.append(answer)  # or whatever
    else:
        passed = True  # Didn't break, therefore passed.
handle_answers(answers)

enter image description here

绿线是我希望它的工作方式(旋转到最接近的值)。红线是当前的工作方式(在GIF上)。

enter image description here

是否可以将旋转动画设置为最接近的值? (在我们的例子中是从335到顺时针13)。也许有比插值更好的方法了?

2 个答案:

答案 0 :(得分:0)

let heading = this.state.heading;
    let oldHeading = this.state.oldHeading;
    const duration = 200;
    if (oldHeading - heading > 180) {
        Animated.timing(
            this.state.spinAnim,
        { 
            toValue: 360,
            duration: duration,
            easing: Easing.linear,
            useNativeDriver: true
        }).start(() => this.state.spinAnim.setValue(0));
    } else if (oldHeading - heading < -180) {
        Animated.timing(
            this.state.spinAnim,
        { 
            toValue: 0,
            duration: duration,
            easing: Easing.linear,
            useNativeDriver: true
        }).start(() => this.state.spinAnim.setValue(360));
    } else {
        Animated.timing(
            this.state.spinAnim,
        { 
            toValue: heading,
            duration: duration,
            easing: Easing.linear,
            useNativeDriver: true
        }).start();
    }

我遇到了同样的问题,所以我的解决方案是每次都保持精确的前一个标题,如果距离大于180,我将使用两个单独的动画。一个从x动画到0,然后将value设置为360(或x设置为360,然后将value设置为0),另一个是“默认”并每次运行。

答案 1 :(得分:0)

这等效于避免CSS旋转过渡中的回滚。

一种方法是基于前一个角度的幅度重新计算下一个角度。您仍然必须使用插值,所发生的变化是,馈送到动画的值将是此函数(credits)的结果,该函数将差值添加到前一个值,并执行一些模检查以猜测最接近的值:

function closestEquivalentAngle(from, to) {
    var delta = ((((to - from) % 360) + 540) % 360) - 180;
    return from + delta;
}

因此,例如,下次您从335度前进到13度时,结果将为373,即原始值加上38度的差。这也可以倒退。只需记住将结果角度的值存储在某个位置即可,因此可以在下一次迭代中将其用作prevAngle

将它们全部拉在一起:

const RotateComp = (props) => {
  const rotationValue = React.useRef(new Animated.Value(0)).current;

  // Animation interpolation
  const rotation = rotationValue.interpolate({
    inputRange: [-360, 360],
    outputRange: ['-360deg', '360deg'],
  });

  React.useEffect(() => {
    // Obtain prevAngle and nextAngle, then...

    Animated.timing(
      rotationValue,
      {
        toValue: closestEquivalentAngle(prevAngle, nextAngle),
        duration: 200,
        useNativeDriver: true,
      },
    ).start();
  }, [rotationValue])

  return (
    // ...
    <Animated.View
      style={{
        ...props.style,
        transform: [{rotate: rotation}],
      }}
    >
      {props.children}
    </Animated.View>
  );
}