在捕捉到间隔的 FlatList 中滑动时,如何检测将捕捉到哪个项目?

Esb*_*ald 7 react-native react-native-scrollview react-native-flatlist

我有一个水平组件<FlatList>,包含 100 个项目(日历天),宽度与屏幕相同。将<FlatList>被设置为捕捉到的间隔类似于屏幕宽度,所以可项之间滑动。

当我滑动到特定日期时,我想更新 UI 以在<FlatList>. 现在我正在使用onMomentumScrollEnd查找最终偏移量和显示在标题中的日期项目。

但是,用户体验不是最佳的,因为在滑动/滚动动画结束之前标题不会更新。

我需要的是一种方法来确定<FlatList>用户一滑动就会捕捉到哪个偏移量。

我想onScroll可能会有用,但是<FlatList>根据我从onScroll.

但是,我可以看到一些 3rd 方模块react-native-snap-carousel正在这样做,使用onScroll,所以我想这是可能的。

我选择不使用,react-native-snap-carousel因为它确实会降低我屏幕上的滑动动画性能。如果模块没有给出明确的答案,请查看代码,因为该模块具有大量我不需要的功能,这些功能是它用于确定下一个snapTo偏移量的代码的一部分

Ste*_*ros 6

要检测 FlatList 中的“对齐”,您可以使用viewabilityConfigonViewableItemsChanged Flatlist 属性。

请参阅下面的代码(针对Hooks组件),其中我在onViewChanged方法中处理“snap”:

import React, {useRef, useState} from 'react';
import {Dimensions, FlatList, View} from 'react-native';

// CLASS COMPONENT API
export class DemoViewabilityConfigClass extends React.Component {
  flatlistRef;
  constructor(props) {
    super(props);
    this.state = {
      activeIndex: 0,
    };
  }

  onViewChanged = ({viewableItems, index}) => {
    console.log('I snapped to', viewableItems);
    if (viewableItems.length > 0) {
      const {item: activeItem, index: activeIndex} = viewableItems[0];
      console.log(activeItem, activeIndex);
      this.setState({activeIndex: activeIndex});
    }
  };

  render() {
    return (
      <FlatList
        ref={ref => (this.flatlistRef = ref)}
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={{
          marginHorizontal: 10,
        }}
        snapToInterval={Dimensions.get('window').width}
        decelerationRate={0}
        overScrollMode={'never'}
        snapToAlignment={'center'}
        data={[
          {
            id: 'something',
            other: 'data',
          },
          {
            id: 'else',
            other: 'data',
          },
        ]}
        onScrollEndDrag={() => console.log('Scroll end')}
        horizontal={true}
        viewabilityConfig={{itemVisiblePercentThreshold: 70}}
        onViewableItemsChanged={this.onViewChanged}
        onScrollToIndexFailed={info => {
          console.log('Scroll failed', info);
          const wait = new Promise(resolve => setTimeout(resolve, 500));
          wait.then(() => {
            this.flatlistRef.current?.scrollToIndex({
              index: info.index,
              animated: true,
            });
          });
        }}
        renderItem={({item, index}) => {
          return (
            <View
              style={{
                marginRight: 20,
                height: 20,
                width: Dimensions.get('window').width - 20,
                backgroundColor: 'red',
              }}
            />
          );
        }}
      />
    );
  }
}

// HOOKS API
export function DemoViewabilityConfigHooks() {
  const flatlistRef = useRef(null);
  const [activeEventIndex, setActiveEventIndex] = useState(0);

  const onViewChanged = React.useRef(({viewableItems}) => {
    console.log('Items ', viewableItems);
    if (viewableItems.length > 0) {
      const {index, item} = viewableItems[0];
      console.log('Active index', index);
      setActiveEventIndex(index);
    }
  });

  const viewConfigRef = React.useRef({viewAreaCoveragePercentThreshold: 50});

  return (
    <FlatList
      ref={flatlistRef}
      showsHorizontalScrollIndicator={false}
      contentContainerStyle={{
        marginHorizontal: 10,
      }}
      snapToInterval={Dimensions.get('window').width}
      decelerationRate={0}
      overScrollMode={'never'}
      snapToAlignment={'center'}
      data={[
        {
          id: 'something',
          other: 'data',
        },
        {
          id: 'else',
          other: 'data',
        },
      ]}
      onScrollEndDrag={() => console.log('Scroll end')}
      horizontal={true}
      viewabilityConfig={viewConfigRef.current}
      onViewableItemsChanged={onViewChanged.current}
      onScrollToIndexFailed={info => {
        console.log('Scroll failed', info);
        const wait = new Promise(resolve => setTimeout(resolve, 500));
        wait.then(() => {
          flatlistRef.current?.scrollToIndex({
            index: info.index,
            animated: true,
          });
        });
      }}
      renderItem={({item, index}) => {
        return (
          <View
            style={{
              marginRight: 20,
              height: 20,
              width: Dimensions.get('window').width - 20,
              backgroundColor: 'red',
            }}
          />
        );
      }}
    />
  );
}


Run Code Online (Sandbox Code Playgroud)

例如,如果您需要更改 onViewChanged 方法内的组件状态,则在使用功能组件/ Hooks API 时需要将这 2 个 props 包装到 Ref() 中。否则,会导致“不支持动态更改 onViewableItemsChanged。错误。此外,您需要使用.current语法将这些 props 传递给 Flalist。

这是 GIF 示例:

在此输入图像描述