React Native SVG Animation 不会为最后一个数组项设置动画

React Native SVG Animation doesn't animate the last array item

我是 React Native Animation 的新手,我正在学习教程,我完全按照他所教的去做,但我没有得到想要的结果。我正在尝试开发一个带有 svg 动画的多页入职屏幕。问题是它工作正常,但是当我到达平面列表中的最后一项时,它不会更新索引,因此最后一个数组项的动画没有完成。

相关代码如下:

注册屏幕:

const data = [
  <EmailComponent />,
  <PasswordComponent />,
  <DPComponent />,
  <AgeComponent />,
];

const RegisterScreen = () => {
  const scrollX = useRef(new Animated.Value(0)).current;
  const [currentIndex, setCurrentIndex] = useState(0);
  const slidesRef = useRef(null);

  const viewableItemsChanged = useCallback(({viewableItems}) => {
    console.log(viewableItems[0]);
    setCurrentIndex(viewableItems[0].index);
  }, []);

  const scrollTo = () => {
    if (currentIndex < data.length - 1) {
      slidesRef.current.scrollToIndex({index: currentIndex + 1});
    } else {
      console.log('Last Item!');
    }
  };

  const goBack = () => {
    if (currentIndex === 0) {
      return;
    }
    slidesRef.current.scrollToIndex({index: currentIndex - 1});
  };

  // console.log(currentIndex);

  return (
    <RegisterationStateProvider>
      <View style={styles.container}>
        <StatusBar barStyle="dark-content" backgroundColor="#ffffff" />
        <SafeAreaView style={styles.back}>
          <TouchableOpacity onPress={goBack} activeOpacity={0.6}>
            <AntDesign name="arrowleft" size={32} color="black" />
          </TouchableOpacity>
        </SafeAreaView>

        <View style={{flex: 3}}>
          <FlatList
            ref={slidesRef}
            scrollEnabled
            data={data}
            keyExtractor={(_, index) => 'key' + index}
            renderItem={({item}) => item}
            horizontal
            showsHorizontalScrollIndicator={false}
            pagingEnabled
            bounces={false}
            onScroll={
              Animated.event(
              [{nativeEvent: {contentOffset: {x: scrollX}}}],
              {useNativeDriver: false},
            )}
            scrollEventThrottle={32}
            onViewableItemsChanged={viewableItemsChanged}
          />
        </View>

        <Dot data={data} scrollX={scrollX} />

        <NextButton
          scrollTo={scrollTo}
          percentage={(currentIndex + 1) * (100 / data.length)}
        />
      </View>
    </RegisterationStateProvider>
  );
};

下一个按钮:

const NextButton = ({percentage, scrollTo}) => {
  const size = 100;
  const strokeWidth = 4;
  const center = size / 2;
  const radius = size / 2 - strokeWidth / 2;
  const circumference = 2 * Math.PI * radius;
  // console.log(percentage);

  const progressAnimation = useRef(new Animated.Value(0)).current;
  const progressRef = useRef(null);

  const animation = toValue => {
    return Animated.timing(progressAnimation, {
      toValue,
      duration: 250,
      useNativeDriver: false,
    }).start();
  };

  useEffect(() => {
    animation(percentage);
  }, [percentage]);

  useEffect(() => {
    progressAnimation.addListener(
      value => {
        const strokeDashoffset =
          circumference - (circumference * value.value) / 100;
        if (progressRef?.current) {
          progressRef.current.setNativeProps({
            strokeDashoffset,
          });
        }
      },
      [percentage],
    );
    return () => {
      progressAnimation.removeAllListeners();
    };
  }, []);

  return (
    <View style={styles.container}>
      <Svg width={size} height={size}>
        <G rotation="-90" origin={center}>
          <Circle
            stroke="#E6E7E8"
            cx={center}
            cy={center}
            r={radius}
            strokeWidth={strokeWidth}
          />
          <Circle
            ref={progressRef}
            stroke="#FF5864"
            cx={center}
            cy={center}
            r={radius}
            strokeWidth={strokeWidth}
            strokeDasharray={circumference}
            strokeDashoffset={circumference}
          />
        </G>
      </Svg>

      <TouchableOpacity
        disabled={false}
        onPress={scrollTo}
        style={styles.button}
        >
        <AntDesign name="arrowright" size={35} color="#fff" />
      </TouchableOpacity>
    </View>
  );
};

我在代码中找不到 error/bug,一切看起来都很好,因为当我在 scrollTo 函数中检查 if (currentIndex < data.length - 1) 时,它应该呈现 index=3 因为 3<4 显然是真的,但不幸的是它不起作用,控制台也没有错误。

下面是 console.log(currentIndex); & console.log(percentage);

的控制台输出
LOG  {"index": 0, "isViewable": true, "item": <EmailComponent />, "key": "key0"}
LOG  {"index": 0, "isViewable": true, "item": <EmailComponent />, "key": "key0"}
LOG  {"index": 1, "isViewable": true, "item": <PasswordComponent />, "key": "key1"}
LOG  {"index": 1, "isViewable": true, "item": <PasswordComponent />, "key": "key1"}
LOG  {"index": 2, "isViewable": true, "item": <DPComponent />, "key": "key2"}
LOG  0
LOG  25
LOG  1
LOG  50
LOG  2
LOG  75

如您所见,即使我在最后一项,动画仍处于 (75%) 270° 且未完全完成,即 (100%) 360° 且 {index:3} 未记录在控制台中,即使我是最后一项数据。

FlatList 中的最后一项未触发

onViewableItemsChanged。降低viewAreaCoveragePercentThreshold中的viewabilityConfig属性https://reactnative.dev/docs/flatlist#viewabilityconfig