【问题标题】:Show different data based on the active carousel item根据活动轮播项目显示不同的数据
【发布时间】:2021-02-15 15:30:28
【问题描述】:

我有一个水平的 ,这是我的 React-native 应用程序中的一个“轮播”,它在屏幕中心显示一个项目以及上一个和下一个项目的边缘。我想在 ScrollView 下方显示数据(课程)。 有人可以告诉我或指向资源,我如何知道屏幕现在正在显示什么项目,然后根据该项目显示数据?我需要计算滚动视图中的当前项目还是传递它作为某个函数的参数?

我的目标:

父组件:

 return (
<View style={styles.screen}>
  <View style={styles.thumbnailScrollContainer}>
    <HorizontalContentScroll
      data={LESSONS_DATA}
    />
  </View>
  <View style={styles.dataScrollContainer}>
    <FlatList numColumns={2} data={lessonsByCategory} renderItem={renderLessonItem} />
  </View>
</View> );

这里是我的水平滚动视图

const HorizontalContentScroll = ({ data}: HorizontalContentProps) => {
  const { width, height } = Dimensions.get('window');
  const scrollX = useRef(new Animated.Value(0)).current;
  const ITEM_SIZE = width * 0.8;

  const getInterval = (offset: any) => {
    // console.log('offset', offset);
  };

  const scrollableData = (data as Array<ContentCategory>).map(
    (item: ContentCategory, index: number) => {
      const inputRange = [
        (index - 1) * ITEM_SIZE,
        index * ITEM_SIZE,
        (index + 1) * ITEM_SIZE,
      ];
      const translateY = scrollX.interpolate({
        inputRange,
        outputRange: [40, 10, 40],
        // extrapolate: 'clamp',
      });

      return (
        <Card
          size="large"
          style={{
            ...styles.titleCard,
            transform: [{ translateY }],
            width: ITEM_SIZE,
          }}
          key={`${item.category}-${index}`}
        >
          <Text>{item.category}</Text>
        </Card>
      );
    }
  );

  return (
    <Animated.ScrollView
      contentContainerStyle={styles.contentContainer}
      horizontal
      onScroll={Animated.event(
        [{ nativeEvent: { contentOffset: { x: scrollX } } }],
        {
          useNativeDriver: true,
          listener: (event) => {
            getInterval(event);
          },
        }
      )}
      scrollEventThrottle={16}
      showsHorizontalScrollIndicator={false}
      bounces={false}
      pagingEnabled
      snapToAlignment="center"
      snapToInterval={330}
      decelerationRate={'fast'}
    >
      {scrollableData}
    </Animated.ScrollView>
  );
};

export default HorizontalContentScroll;

我想我必须在这个 map 函数中做一些事情,比如将当前项目传递给我的父组件,但是如何?如果我尝试调用在父级中设置状态的函数,则会收到“警告:无法从不同组件的函数体内更新组件”的错误。

const scrollableData = (data as Array<ContentCategory>).map(
    (item: ContentCategory, index: number) => {
      const inputRange = [
        (index - 1) * ITEM_SIZE,
        index * ITEM_SIZE,
        (index + 1) * ITEM_SIZE,
      ];

      const translateY = scrollX.interpolate({
        inputRange,
        outputRange: [40, 10, 40],
      });

      // filterLessonsInTheParent(item)
      
      return (
        <Card
          size="large"
          style={{
            ...styles.titleCard,
            transform: [{ translateY }],
            width: ITEM_SIZE,
          }}
          key={`${item.category}-${index}`}
        >
          <Text>{item.category}</Text>
        </Card>
      );
    }

【问题讨论】:

    标签: javascript reactjs react-native animation carousel


    【解决方案1】:

    好的,我解决了。

    我使用了 Animated.Flatlist 而不是 Animated.Scrollview,这样我就可以使用 onViewableItemsChanged 属性,然后我必须将我的组件重构为一个类组件,以便 viewabilityConfig 属性能够正常工作。

    我在更新本地状态的 useCallback 函数中将当前可查看项传递给父项。然后我使用它和 React Pure Component 来避免重新渲染我的HorizontalContentScroll,这会弄乱动画位置。 (我不知道这是否是最理想的方式,但到目前为止它有效)。

    // Parent
    const handleViewableChange = useCallback((item: ContentCategory) => {
        setContentsToShow((prevItem) => item.contents);
      }, []);
    
      return (
        <View style={styles.screen}>
          <View style={styles.thumbnailScrollContainer}>
            <HorizontalContentScroll
              data={LESSONS_DATA}
              onViewableChange={handleViewableChange }
            />
          </View>
          <View>
    
              <FlatList
                numColumns={2}
                data={contentsToShow}
                renderItem={renderLessonItem}
              /> 
    
    // HorizontalContentScroll
    class HorizontalContentScroll extends PureComponent<HoriProps, any> {
      viewabilityConfig: { viewAreaCoveragePercentThreshold: number };
      scrollX: any;
      constructor(props: any) {
        super(props);
    
        this.handleViewableItemsChanged = this.handleViewableItemsChanged.bind(
          this
        );
        this.viewabilityConfig = { viewAreaCoveragePercentThreshold: 50 };
      }
    
      handleViewableItemsChanged = (info: any) => {
        const currItemInView = info.viewableItems[0].item;
        this.props.onViewableChange(currItemInView);
      };
    
      render() {
        const { data } = this.props;
        const { width, height } = Dimensions.get('window');
        const scrollX = new Animated.Value(0);
        const ITEM_SIZE = width * 0.8;
    
        return (
          <Animated.FlatList
            data={data}
            contentContainerStyle={styles.contentContainer}
            horizontal
            pagingEnabled
            onViewableItemsChanged={this.handleViewableItemsChanged}
            viewabilityConfig={this.viewabilityConfig}
            scrollEventThrottle={16}
            showsHorizontalScrollIndicator={false}
            bounces={false}
            snapToAlignment="center"
            snapToInterval={330}
            decelerationRate={'fast'}
            onScroll={Animated.event(
              [{ nativeEvent: { contentOffset: { x: scrollX } } }],
              {
                useNativeDriver: true,
              }
            )}
            renderItem={({
              item,
              index,
            }: {
              item: ContentCategory;
              index: number;
            }) => {
              const inputRange = [
                (index - 1) * ITEM_SIZE,
                index * ITEM_SIZE,
                (index + 1) * ITEM_SIZE,
              ];
              const translateY = scrollX.interpolate({
                inputRange,
                // [x, y, x]
                outputRange: [40, 10, 40],
                // extrapolate: 'clamp',
              });
              return (
                <Card
                  size="large"
                  style={{
                    ...styles.titleCard,
                    transform: [{ translateY }],
                    width: ITEM_SIZE,
                  }}
                  key={`${item.category}-${index}`}
                >
                  <Text style={styles.categoryText}>{item.category}</Text>
                </Card>
              );
            }}
          />
        );
      }
    }
    
    export default HorizontalContentScroll;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      相关资源
      最近更新 更多