动画后更新动画视图的颜色

Update color of animated view after animation

我正在创建一个 React Native 应用程序,想在用户触摸动画视图后更改它的背景颜色。有关更多上下文,视图是正方形的,我在安装组件时将其旋转 225 度。如果用户触摸正方形,它会动画翻转动作并显示正方形的另一侧,这是不同的颜色。我用来执行此操作的代码如下所示:

const app = (props) => {
   let colors = [color1, color2, color3, ...];
   let index = 0;
   let animatedValue= new Animated.Value(0);
   let squareSpin = new Animated.Value(0);
   let val = 0;

  useEffect(() => {
    Animated.timing(squareSpin, {
      toValue: 1,
      duration: 3000,
      easing: Easing.linear,
    }).start();
  }, []);

  const startSpin = squareSpin.interpolate({
    inputRange: [0, 1],
    outputRange: ["0deg", "225deg"],
  });

  animatedValue.addListener(({ value }) => {
    val = value;
  });

  let frontInt= animatedValue.interpolate({
    inputRange: [0, 180],
    outputRange: ["0deg", "180deg"],
  });

  let backInt = animatedValue.interpolate({
    inputRange: [0, 180],
    outputRange: ["180deg", "360deg"],
  });

  let opacityFront = animatedValue.interpolate({
    inputRange: [89, 90],
    outputRange: [1, 0],
  });


  let opacityBack = animatedValue.interpolate({
    inputRange: [89, 90],
    outputRange: [0, 1],
  });

  const flip= () => {
    if (val>= 90) {
      Animated.spring(animatedValue, {
        toValue: 0,
        friction: 6,
        tension: 8,
      }).start();
    } else {
      Animated.spring(animatedValue, {
        toValue: 180,
        friction: 6,
        tension: 8,
      }).start();
    }
  };

  const frontAnimated = {
    transform: [{ rotateY: frontInt }],
  };
  const backAnimated = {
    transform: [{ rotateY: backInt}],
  };

  return (
     <Animated.View
        style={{transform: [{ rotate: startSpin }] }}
      >
         <TouchableWithoutFeedback
              onPress={() => {
                index++;
                flip();
              }}>
            <Animated.View
                style={[
                  styles.shape,
                  {
                    backgroundColor:
                      colors[index % colors.length],
                  },
                  frontAnimated ,
                  { opacity: opacityFront },
                ]}
              >
              </Animated.View>
              <Animated.View
                style={[
                  styles.shape,
                  {
                    backgroundColor:
                      colors[(index + 1) % colors.length],
                  },
                  { position: "absolute" },
                  backAnimated ,
                  { opacity: opacityBack },
                ]}
              ></Animated.View>
          </TouchableWithoutFeedback>
     <Animated.View>
  )

}

问题:动画效果都很好,但问题是我翻转的正方形的每一侧只能呈现一种颜色。请注意,在 colors 数组中,方块应根据用户按下方块的次数显示多种颜色。然而,这并没有发生,正方形的每一侧总是开始时的颜色(color1 用于正方形的顶部,color2 用于正方形的底部)。我认为发生这种情况是因为 view 没有意识到索引正在发生变化,因为它永远不会再次呈现。或者,由于 Animated.View 的某些属性,它可能根本无法改变它的颜色,我不太确定。我尝试在使用 useState 按下正方形时强制进行渲染,但这导致正方形撤消了组件安装时发生的旋转,这是我不希望发生的。如何让视图的背景颜色根据用户点击的次数而改变?

谢谢!

内部渲染方法

const BackgroundColorConfig = this.Animation.interpolate(
            {
                inputRange: [ 0, 0.2, 0.4, 0.6, 0.8, 1 ],
                
                outputRange: [ '#f6f6f6', '#f6f6f6', '#f6f6f6', LIGHT_RED_COLOR, LIGHT_RED_COLOR, LIGHT_RED_COLOR ]
     
            });


usage backgroundColor:BackgroundColorConfig

将以上属性赋予您的组件(它应该在 Animated.View 标签下)

制作一个调用动画的函数,并在 componentDidMount 或按钮点击时使用它

Define this.Animated = new Animated.value(0)

在构造函数中

StartBackgroundColorAnimation = (value) =>
{
    Animated.timing(
        this.Animation,
        {
            toValue: value,
            duration: 600
        }
    ).start();
}

我能够通过使用两个不同的颜色插值值来解决这个问题。

let colorSideOne = colorValue1.interpolate({
  inputRange: [...Array(colors.length)].map((_, index) => index),
  outputRange: colors,
});
let colorSideTwo = colorValue2.interpolate({
  inputRange: [...Array(colors.length)].map((_, index) => index),
  outputRange: colors,
});

并使用这些值将颜色设置为卡片的背景

<Animated.View
  style={[
    styles.shape,
    {
      backgroundColor: colorSideOne,
    },
    frontAnimated,
    { opacity: opacityFront },
  ]}>
</Animated.View>
<Animated.View
  style={[
    styles.shape,
    {
      backgroundColor: colorSideTwo,
    },
    frontAnimated,
    { opacity: opacityFront },
  ]}>
</Animated.View>

您现在只需根据索引正确更新 colorValues。

注意前后值需要交替进行

<TouchableWithoutFeedback
  style={{
    borderWidth: 2,
    borderColor: 'red',
  }}
  onPress={() => {
    index++;
    //side = side === 'front' ? 'back' : 'front';
    //console.log('side',side);
    // console.log('index',index, 'color length', colors.length);
    if (index & 1) {
      colorValue1.setValue((index + 1) % colors.length);
    } else {
      colorValue2.setValue((index + 1) % colors.length);
    }
    // console.log('color value', colorValue1, colorValue2);
    flip();
  }}>
    ....
    ....

为了清楚起见,我附上了这个博览会 demo

希望这就是您所期待的!