在 React Native 中获取 ScrollView 的当前滚动位置

新手上路,请多包涵

是否可以获得当前滚动位置,或者 React Native 中 <ScrollView> 组件的当前页面?

所以像:

 <ScrollView
  horizontal={true}
  pagingEnabled={true}
  onScrollAnimationEnd={() => {
      // get this scrollview's current page or x/y scroll position
  }}>
  this.state.data.map(function(e, i) {
      <ImageCt key={i}></ImageCt>
  })
</ScrollView>

原文由 Sang 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.1k
2 个回答

尝试。

 <ScrollView onScroll={this.handleScroll} />

接着:

 handleScroll: function(event: Object) {
 console.log(event.nativeEvent.contentOffset.y);
},

在另一种情况下,假设您还想实现分页指示器,您将希望通过以下方式走得更远:

 <ScrollView
     onScroll={Animated.event([{ nativeEvent: { contentOffset: { x:
     scrollX } } }], {listener: (event) => handleScroll(event)})}
     scrollEventThrottle={16}
>
   ...some content
</ScrollView>

其中 scrollX 将是一个动画值,您可以将其用于分页,并且您的 handleScroll 函数可以采用以下形式:

   const handleScroll = (event) => {
    const positionX = event.nativeEvent.contentOffset.x;
    const positionY = event.nativeEvent.contentOffset.y;
  };

原文由 brad oyler 发布,翻译遵循 CC BY-SA 4.0 许可协议

免责声明:以下内容主要是我自己在 React Native 0.50 中的实验结果。 ScrollView 文档 目前缺少下面涵盖的许多信息;例如 onScrollEndDrag 完全没有记录。由于此处的所有内容都依赖于未记录的行为,因此很遗憾,我无法保证此信息在一年甚至一个月后仍然正确。

此外,下面的所有内容都假定一个纯垂直滚动视图,我们感兴趣的是其 y 偏移量;如果需要,转换为 x 偏移量,希望对读者来说是一个简单的练习。


ScrollView 上的各种事件处理程序采用 event 并让您通过 event.nativeEvent.contentOffset.y 获取当前滚动位置。其中一些处理程序在 Android 和 iOS 之间的行为略有不同,如下所述。

onScroll

在安卓上

在用户滚动时触发每一帧,在用户释放滚动视图后滚动视图滑动时在每一帧触发,在滚动视图停止时在最后一帧触发,以及每当滚动视图的偏移量因其帧而改变时触发变化(例如,由于从横向到纵向的旋转)。

在 iOS 上

当用户拖动或滚动视图滑动时触发,频率由 scrollEventThrottle 决定,当 scrollEventThrottle={16} 时每帧最多一次。 如果 用户在滚动视图有足够的动量可以滑动时释放滚动视图,则 onScroll 处理程序也会在滑动结束后停止时触发。但是,如果用户在静止时拖动然后释放滚动视图, onScroll 不能 保证触发最终位置,除非 scrollEventThrottle 已设置为 onScroll 触发滚动的每一帧。

设置 scrollEventThrottle={16} 会产生性能成本,可以通过将其设置为更大的数字来降低性能成本。然而,这意味着 onScroll 不会触发每一帧。

onMomentumScrollEnd

当滚动视图在滑动后停止时触发。如果用户在滚动视图静止时释放滚动视图,则根本不会触发,这样它就不会滑动。

onScrollEndDrag

当用户停止拖动滚动视图时触发 - 无论滚动视图是保持静止还是开始滑动。


鉴于这些行为差异,跟踪偏移量的最佳方法取决于您的具体情况。在最复杂的情况下(您需要支持 Android 和 iOS,包括处理 ScrollView 的帧由于旋转而发生的变化,并且您不想通过设置接受 Android 的性能损失 scrollEventThrottle 到 16),并且您还需要处理滚动视图中 内容 的更改,那真是一团糟。

最简单的情况是如果你只需要处理 Android;只需使用 onScroll

 <ScrollView
  onScroll={event => {
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
>

为了额外支持 iOS, 如果 您乐于触发 onScroll 处理每一帧并接受其性能影响, 如果 您不需要处理帧变化,那么它只多一点复杂的:

 <ScrollView
  onScroll={event => {
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  scrollEventThrottle={16}
>

为了减少 iOS 上的性能开销,同时仍然保证我们记录滚动视图停留的任何位置,我们可以增加 scrollEventThrottle 并额外提供一个 onScrollEndDrag 处理程序:

 <ScrollView
  onScroll={event => {
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  onScrollEndDrag={event => {
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  scrollEventThrottle={160}
>

但是如果我们想要处理框架变化(例如,因为我们允许设备旋转,改变滚动视图框架的可用高度)和/或内容变化,那么我们必须另外实现 onContentSizeChangeonLayout 跟踪滚动视图的框架及其内容的高度,从而不断计算 最大 可能的偏移量并推断偏移量何时因框架或内容大小更改而自动减小:

 <ScrollView
  onLayout={event => {
    this.frameHeight = event.nativeEvent.layout.height;
    const maxOffset = this.contentHeight - this.frameHeight;
    if (maxOffset < this.yOffset) {
      this.yOffset = maxOffset;
    }
  }}
  onContentSizeChange={(contentWidth, contentHeight) => {
    this.contentHeight = contentHeight;
    const maxOffset = this.contentHeight - this.frameHeight;
    if (maxOffset < this.yOffset) {
      this.yOffset = maxOffset;
    }
  }}
  onScroll={event => {
    this.yOffset = event.nativeEvent.contentOffset.y;
  }}
  onScrollEndDrag={event => {
    this.yOffset = event.nativeEvent.contentOffset.y;
  }}
  scrollEventThrottle={160}
>

是的,这太可怕了。我也不是 100% 确定它在您 同时 更改滚动视图的框架和内容的大小的情况下总是能正常工作。但这是我能想到的最好的,并且在 这个特性被添加到框架本身 之前,我认为这是任何人都能做到的最好的。

原文由 Mark Amery 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题