在动画平面列表中反应原生错误

时间:2021-06-29 12:03:13

标签: react-native

我在水平 FlatList 中显示了不同的项目列表。 所以基本上我有不同的列表:

  • 列表A
  • 列表 B
  • 列表 C ...

它们都是水平的,并且共享相同的逻辑。

我正在使用 Animated 根据项目的索引通过插值为 flatlist 设置动画。

它可以正常显示某些列表但不能显示其他列表,例如索引会因一个列表而异,但我不明白发生了什么,因为所有列表都应从索引 [0] 开始

这里你可以看一个截图来理解: FlatList bug display

如您所见,第一个列表正确显示在屏幕上,并被插值为正常大小的 1.3 倍,但第二个共享完全相同的逻辑没有被插值。

三个主要组成部分:

  • 允许显示多个列表的部分列表:“BlockHomeChanelList”
  • 使用 flatlList 处理动画逻辑的主要组件:“阻止家庭频道列表”
  • 渲染组件“阻止视频”

已编辑(添加此块) BlockHomeChanelList:

export default function BlockHomeChannelList({ showModal = false, startSlice = 0, endSlice = 1 }) {
  const categories = useSelector(getCategoriesList);

  return (
    <SectionList
      contentContainerStyle={{ marginLeft: MixinsStyles.wp(0) }}
      scrollEnabled={false}
      sections={categories.slice(startSlice, endSlice)}
      keyExtractor={(item) => item.id + item.name}
      renderItem={({ item, section: { name } }) => (
        <BlockHomeChannelItem
          showPlus={true}
          showModal={showModal}
          categoryItem={item}
          name={name}
        />
      )}
    />
  );
}

在该示例中,仅显示一个类别(通过使用幻灯片),并且在该类别内有四个列表。 像一个类别(体育):和显示在水平平面列表中的子类别(篮子、脚、曲棍球......)

阻止家庭频道列表:

export default function BlockHomeChannelItem({
  categoryItem,
  titleButton = "Voir toutes les vidéos",
  name,
  // showPlus = false,
}) {
  const navigation = useNavigation();
  const token = useSelector((state) => state.user.tokens.token);
  const [loading, setLoading] = React.useState(false);
  const [playlist, setPlaylist] = React.useState({});

  // Flatlist
  const CARD_WIDTH = MixinsStyles.wp(196);
  const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
  const animated = useRef(new Animated.Value(0)).current;
  const padding = (width - CARD_WIDTH) / 2;
  const marginRight = MixinsStyles.wp(18);
  const flatListRef = useRef(null);


  React.useEffect(() => {
    if (token && categoryItem.id && !playlist?.id) {
      getChannelPlaylist(token, categoryItem.id).then((data) => {
        setPlaylist(data);
        setLoading(false);
      });
    }
  }, [token, categoryItem.id, playlist?.id]);

  if (loading || !playlist?.videos?.length || !playlist?.activeVideoCount) {
    return null;
  }
  return (
    <View style={{ marginBottom: MixinsStyles.hp(35) }}>

     *...TextTitleCode*

      <AnimatedFlatList
        data={playlist?.videos}
        horizontal
        ref={flatListRef}
        showsHorizontalScrollIndicator={false}
        keyExtractor={(item) => item}
        onScroll={Animated.event(
          [
            {
              nativeEvent: {
                contentOffset: {
                  x: animated,
                },
              },
            },
          ],
          { useNativeDriver: true }
        )}
        scrollEventThrottle={16}
        getItemLayout={(data, index) => ({
          length: CARD_WIDTH + marginRight,
          offset: (CARD_WIDTH + marginRight) * index,
          index,
        })}
        snapToInterval={CARD_WIDTH + marginRight}
        contentContainerStyle={{ paddingHorizontal: padding, height: MixinsStyles.hp(200) }}
        renderItem={({ item, index }) => {
          const inputRange = [
            (index - 1) * (CARD_WIDTH + marginRight), //
            index * (CARD_WIDTH + marginRight),
            (index + 1) * (CARD_WIDTH + marginRight),
          ];
          const scale = animated.interpolate({
            inputRange,
            outputRange: [1, 1.28, 1],
            extrapolate: "clamp",
          });
          const opacity = animated.interpolate({
            inputRange,
            outputRange: [0.5, 1, 0.5],
            extrapolate: "clamp",
          });
          const myScale = { transform: [{ scale }] };
          return (
            <BlockVideo
              showModal={showModal}
              item={item}
              resume={resume}
              favorite={favorite}
              animatedStyle={{ opacity, myScale }}
            />
          );
        }}
      />
     *....buttonCode*
    </View>
  );
}

块视频:

export default function BlockVideo({
  item,
  resume,
  favorite,
  animatedStyle,
}) {
  const dispatch = useDispatch();
  const navigation = useNavigation();

  const video = useSelector((state) =>
    state.videos.filter((element) => !!element.active).find((element) => element["@id"] === item)
  );

  if (!video?.id) {
    return null;
  }

  return (
       <Animated.View
      style={[
        animatedStyle.myScale,
        {
          opacity: animatedStyle.opacity,
          alignSelf: "center",
          marginRight: MixinsStyles.wp(36),
        },
      ]}
    >
      <TouchableOpacity
        onPress={...code}
      >
        <ImageBackground
          borderRadius={5}
          style={[
            styles.containerImageBackground,
            { width: search ? "100%" : MixinsStyles.hp(196) },
          ]}
          source={
            video?.picture?.contentUrl
              ? { uri: video?.picture?.contentUrl }
              : AssetsImg.EXPERT_PICTURE
          }
        >
          <GradientImageBackground variant="black" style={styles.gradientImage}>
            {favorite && (
              <AntDesign style={styles.iconFavorite} name="star" size={13} color="#FF0000" />
            )}
            <View style={styles.textPosition}>
              <SharedText textAlign="center" size="12" family="bold">
                {video?.name}
              </SharedText>
              {resume && <ProgressVideoBlock width={50} />}
            </View>
          </GradientImageBackground>
        </ImageBackground>
      </TouchableOpacity>
    </Animated.View>
  );
}

Stylesheet: {...some code}

如果我像这样改变输入范围,它会反转工作项目:

 const inputRange = [
            (index - 2) * (CARD_WIDTH + marginRight), //
            (index -1) * (CARD_WIDTH + marginRight),
            (index) * (CARD_WIDTH + marginRight),
          ];

所以问题是如何为我的所有列表正确显示项目? 我的代码出了什么问题?

非常感谢

1 个答案:

答案 0 :(得分:0)

好的,所以我发现了我的代码出了什么问题。 flatlist 背后的逻辑很好。

问题出在最后一个组件“BlockVideo”上,这里:

 const video = useSelector((state) =>
    state.videos.filter((element) => !!element.active).find((element) => element["@id"] === item)
  );

  if (!video?.id) {
    return null;
  }

由于它通过 id 过滤元素并且不显示没有 id 的项目,元素的索引仍然相同,但屏幕上没有显示任何内容,从而产生了间隙