ScrollToIndex 滚动效果不适用于 0 索引(React Native

问题描述 投票:0回答:1

目前发生的事情是我有 4 个类别,即:全部、类别 1、类别 2 和类别 3

现在的情况是,如果我来自所有类别并选择类别 1,则滚动效果动画效果完美,同样适用于所有 -> 类别 2、所有 -> 类别 3 或类别 1 -> 类别 2 等等。

现在,如果我像从类别 3 -> 类别 2 那样反转,它也可以正常工作,但是当我尝试类别 3 或类别 2 -> 所有类别时,滚动效果动画不起作用。

这是我的代码

interface Item {
  id: string;
  title: string;
}

const getItemMargin = (isFirstIndex: boolean, isLastIndex: boolean) => {
  return {
    marginLeft: isFirstIndex ? 24 : 0,
    marginRight: isLastIndex ? 24 : 8,
  };
};

interface CSProps<T extends Item> extends ViewProps {
  items: T[];
  onSelectItem: (id: T['id']) => void;
  selectedId: string;
  // categoryIndex: number;
}

const CategoryList = <T extends Item>({
  style,
  items,
  onSelectItem,
  selectedId,
  // categoryIndex,
  ...rest
}: CSProps<T>): JSX.Element => {
  const {t} = useTranslation();
  const flatList = useRef<FlatList>(null);
  const [cIndex, setCIndex] = useState<number>(0);

  useEffect(() => {
    if (selectedId === 'all') {
      setCIndex(0);
    } else if (selectedId === 'category 1') {
      setCIndex(1);
    } else if (selectedId === 'category 2') {
      setCIndex(2);
    } else {
      setCIndex(3);
    }

    const timeout = setTimeout(() => {
      console.log(`Check cIndex : ${cIndex}`);
      flatList?.current?.scrollToIndex({
        index: cIndex,
        animated: true,
        viewOffset: 10,
      });
    }, 100); // You can adjust the delay as needed

    return () => clearTimeout(timeout);
  }, [cIndex, items.length, selectedId]);

  /**
   * For smooth transition of category tab on FlatList
   * @param data
   * @param index
   * @returns
   */
  const getItemLayout = (data: any, index: any) => {
    return {
      length: styles.item.height,
      offset: styles.item.height * index,
      index,
    };
  };

  const onMomentumScrollEnd = (event: any) => {
    const windowWidth = Dimensions.get('window').width;
    const currentIndex = Math.round(
      event.nativeEvent.contentOffset.x / windowWidth,
    );
    if (currentIndex !== cIndex) {
      console.log(`Check cIndex: ${currentIndex}`);
      setCIndex(currentIndex);
    }
  };

  const renderItem = ({item, index}: {item: T; index: Number}) => {
    const backgroundColor =
      item.id === selectedId
        ? Colors.PRIMARY_01_BLUE_4
        : Colors.PRIMARY_03_WHITE;
    const color =
      item.id === selectedId
        ? Colors.PRIMARY_03_WHITE
        : Colors.PRIMARY_01_BLUE_4;

    const borderWidth = item.id === selectedId ? 0 : 1;

    const isFirstIndex = index === 0;
    const isLastIndex = index === items.length - 1;

    return (
      <TouchableOpacity
        testID={item.title.replace(/[A-Z]/g, c => c.toLowerCase())}
        onPress={() => onSelectItem(item.id)}
        style={[
          styles.item,
          {backgroundColor},
          {borderWidth},
          getItemMargin(isFirstIndex, isLastIndex),
        ]}>
        <Text style={[styles.title, {color}]}>{t(item.title)}</Text>
      </TouchableOpacity>
    );
  };

  return (
    <View style={style} {...rest}>
      <FlatList
        ref={flatList}
        horizontal
        // initialScrollIndex={cIndex}
        data={items}
        renderItem={renderItem}
        keyExtractor={({id}) => String(id)}
        extraData={selectedId}
        showsHorizontalScrollIndicator={false}
        onMomentumScrollEnd={onMomentumScrollEnd}
        snapToAlignment="center"
        onScrollToIndexFailed={info =>
          setTimeout(() => {
            console.log(
              `Check if failed to scrollIndeX: ${JSON.stringify(info)}`,
            );
            flatList.current?.scrollToIndex({
              index: info.index,
              animated: false,
            });
          }, 500)
        }
        getItemLayout={getItemLayout}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  input: {
    ...Typography.BODY_2_16_BOOK,
    borderBottomColor: Colors.PRIMARY_03_GREY_3,
    borderBottomWidth: 0.7,
    paddingVertical: 12,
  },
  inputActive: {
    borderBottomColor: Colors.PRIMARY_01_BLUE_4,
  },
  item: {
    borderRadius: 16,
    borderStyle: 'solid',
    borderColor: Colors.PRIMARY_03_GREY_3,
    paddingHorizontal: 16,
    height: 28,
    justifyContent: 'center',
    alignItems: 'flex-start',
  },
  title: {
    ...Typography.REMARK_1_13_MEDIUM,
  },
});
android ios react-native mobile
1个回答
0
投票

根据代码和您描述的情况,问题似乎来自从特定类别返回“所有”类别时管理滚动的方式。一个潜在的问题可能是,当您从特定类别导航到“全部”类别时,cIndex 状态未正确更改。截至目前,selectedId 值决定了 cIndex 状态的设置方式,并且仅当 selectedId 状态更改时才会更改。然而,当从特定类别浏览到“全部”类别时,selectedId 值并没有改变,这意味着 cIndex 状态没有被更新。

useEffect(() => {
  let newIndex;
  if (selectedId === 'all') {
    newIndex = 0;
  } else {
    newIndex = items.findIndex((item) => item.id === selectedId);
  }

  setCIndex(newIndex);  // Update the state

  const timeout = setTimeout(() => {
    console.log(`Check newIndex: ${newIndex}`);
    flatList?.current?.scrollToIndex({
      index: newIndex,
      animated: true,
      viewOffset: 10,
    });
  }, 100);

  return () => clearTimeout(timeout);
}, [selectedId, items]);

如果偏移值为零,可以通过更新getItemLayout函数将其调整为零,以验证索引值是否为零。

const getItemLayout = (data: any, index: any) => {
  const offset = index === 0 ? 0 : styles.item.height * index;
  return {
    length: styles.item.height,
    offset,
    index,
  };
};
© www.soinside.com 2019 - 2024. All rights reserved.