如何在 RN 平面列表中获取当前可见的索引

Posted

技术标签:

【中文标题】如何在 RN 平面列表中获取当前可见的索引【英文标题】:How to get currently visible index in RN flat list 【发布时间】:2018-02-02 17:30:56 【问题描述】:

我有一个水平平面列表,其中每个项目都是width:300 我要做的就是获取当前可见项目的索引。

<FlatList 
            onScroll=(e) => this.handleScroll(e) 
            horizontal=true
            data=this.state.data
            renderItem...

试过这个:

handleScroll(event) 
    let index = Math.ceil(
      event.nativeEvent.contentOffset.x / 300
    );

还有这样的:

handleScroll(event) 
  let contentOffset = event.nativeEvent.contentOffset;
  let index = Math.floor(contentOffset.x / 300);

但没有什么是准确的,我总是向上或向下一个索引。 我做错了什么以及如何在平面列表中获取正确的当前索引?例如,我要列出列表中第 8 位的项目,但我得到索引 9 或 10。

【问题讨论】:

【参考方案1】:

UPD。感谢@ch271828n 指出不应更新 onViewableItemsChanged

你可以使用 FlatList onViewableItemsChanged prop 来得到你想要的。

class Test extends React.Component 
  onViewableItemsChanged = ( viewableItems, changed ) => 
    console.log("Visible items are", viewableItems);
    console.log("Changed in this iteration", changed);
  

  render () => 
    return (
      <FlatList
        onViewableItemsChanged=this.onViewableItemsChanged 
        viewabilityConfig=
          itemVisiblePercentThreshold: 50
        
      />
    )
  

viewabilityConfig 可以通过可见性设置帮助您制作任何您想要的东西。在代码示例中,50 表示如果该项目可见超过 50%,则该项目被视为可见。

配置结构见here

【讨论】:

但是我怎么知道要使用哪些数据。因为项目是 300p 宽,如果它在中间,我会看到 20p 左右的项目,好的,我可以得到中间的。但是如果有两个项目如何选择下一个来获取它的数据。 此回调将所有三个项目返回为可见。只有完全消失的项目才会被标记为不可见。 我用图片更新了问题。当我在图像上看到两个项目时。我只需要获取一个项目数据(可能是比另一个更可见的项目数据)。这个回调有可能吗? 我更新了我的答案。我认为你现在可以尝试价值并得到你真正想要的 在 react native 0.54 中说:ExceptionsManager.js:65 Invariant Violation: Change on ViewableItemsChanged on the fly is not supported【参考方案2】:
this.handleScroll = (event) => 
  let yOffset = event.nativeEvent.contentOffset.y
  let contentHeight = event.nativeEvent.contentSize.height
  let value = yOffset / contentHeight


<FlatList onScroll=this.handleScroll />

获取舍入值以计算页码/索引。

【讨论】:

这个放在哪里? 好建议。在 android 上,onViewableItemsChanged 有时会将缓存的项目报告为可见项目。所以使用 handleScroll 或 onMomentumScrollEnd 与这个建议的计算要好得多。【参考方案3】:

非常感谢投票最多的答案 :) 但是,当我尝试它时它不起作用,并引发错误说 changing onViewableItemsChanged on the fly is not supported。经过一番搜索,我找到了解决方案here。这是可以无错误运行的完整代码。关键是这两个配置应该放在 类属性 中,而不是放在 render() 函数中。

class MyComponent extends Component   
  _onViewableItemsChanged = ( viewableItems, changed ) => 
    console.log("Visible items are", viewableItems);
    console.log("Changed in this iteration", changed);
  ;

  _viewabilityConfig = 
    itemVisiblePercentThreshold: 50
  ;

  render() 
    return (
        <FlatList
          onViewableItemsChanged=this._onViewableItemsChanged
          viewabilityConfig=this._viewabilityConfig
          ...this.props
        />
      </View>
    );
  

【讨论】:

我也遇到了这个问题,但我使用的是功能组件,而不是类。你有什么想法可以帮助我吗? 嗯,也许是useCallback?我已经很多年没有写过 React... @Josiah 你得到答案了吗? 聚会有点晚了,但这里是 Github 上问题的链接,其中一位贡献者提出了功能组件的解决方案。希望它会帮助某人github.com/facebook/react-native/issues/…【参考方案4】:

与@fzyzcjy 和@Roman 的答案有关。在 react 中,16.8+ 你可以使用useCallback 来处理changing onViewableItemsChanged on the fly is not supported 错误。

    function MyComponent(props) 
        const _onViewableItemsChanged = useCallback(( viewableItems, changed ) => 
            console.log("Visible items are", viewableItems);
            console.log("Changed in this iteration", changed);
        , []);
    
        const _viewabilityConfig = 
            itemVisiblePercentThreshold: 50
        
    
        return <FlatList
                onViewableItemsChanged=_onViewableItemsChanged
                viewabilityConfig=_viewabilityConfig
                ...props
            />;
    

【讨论】:

_viewabilityConfig 应该使用 useMemo 创建或将其放在模块范围内的函数 MyComponent() 之外 我能问一下为什么吗? 最终用它来根据屏幕上的可见项目做一些事情,谢谢【参考方案5】:

在你的情况下,我猜你可能会忽略 paddingmargin 的项目。 contentOffsetXcontentOffsetY 应该是 firstViewableItemIndex * (itemWidth + item padding or margin)。

作为其他答案,onViewableItemsChanged 将是满足您要求的更好选择。我写了一篇关于如何使用它以及如何实现它的文章。 https://suelan.github.io/2020/01/21/onViewableItemsChanged/

【讨论】:

【参考方案6】:

有点晚了,但对我来说功能组件不同......

如果您使用的是功能组件,请这样做:

  const onScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => 
    const slideSize = event.nativeEvent.layoutMeasurement.width;
    const index = event.nativeEvent.contentOffset.x / slideSize;
    const roundIndex = Math.round(index);
    console.log("roundIndex:", roundIndex);
  , []);

然后在你的 FlatList 上

<FlatList
      data=[2, 3]
      horizontal=true
      pagingEnabled=true
      style= flex: 1 
      showsHorizontalScrollIndicator=false
      renderItem=renderItem
      onScroll=onScroll
    />

【讨论】:

在这种情况下,roundIndex 始终为 0 @manuel

以上是关于如何在 RN 平面列表中获取当前可见的索引的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SwiftUI 中的列表中获取屏幕行?

如何在列表视图索引中切换子元素的可见性?

IGListKit:获取当前可见的单元格索引

在jetpack compose LazyColumn中获取最后一个可见的项目索引

如何在本机反应中从平面列表中设置 Json 数组

IOS swift我可以从TableViewCell中获取当前可见视图吗