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

时间:2015-04-07 23:35:02

标签: ios reactjs react-native

是否可以在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>

12 个答案:

答案 0 :(得分:160)

尝试。

<ScrollView onScroll={this.handleScroll} />

然后:

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

答案 1 :(得分:36)

免责声明:以下内容主要是我在React Native 0.50中进行实验的结果。 ScrollView documentation目前缺少以下所涵盖的大部分信息;例如onScrollEndDrag完全没有记录。由于这里的一切都依赖于无证件的行为,遗憾的是我不会承诺这些信息在一年甚至一个月后仍然是正确的。

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

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

onScroll

在Android上

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

在iOS上

在用户拖动或滚动视图滑动时触发,频率由scrollEventThrottle确定,scrollEventThrottle={16}时每帧最多一次。 如果用户释放滚动视图,同时它有足够的动力滑行,onScroll处理程序也会在滑行后休息时触发。但是,如果用户在静止时拖动然后释放滚动视图,则onScroll 保证为最终位置触发,除非scrollEventThrottle已设置为onScroll {1}}会触发滚动的每一帧。

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

onMomentumScrollEnd

滑动后滚动视图停止时触发。如果用户在静止时释放滚动视图使其不会滑动,则根本不会触发。

onScrollEndDrag

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

鉴于行为的这些差异,跟踪偏移的最佳方式取决于您的确切情况。在最复杂的情​​况下(您需要支持Android和iOS,包括因轮换而处理ScrollView框架中的更改,并且您不希望在设置{{1}时接受Android上的性能损失你需要在滚动视图中处理对内容的更改,然后这是一个非常糟糕的混乱。

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

onScroll

要另外支持iOS, if ,您很乐意每帧触发<ScrollView onScroll={event => { this.yOffset = event.nativeEvent.contentOffset.y }} > 处理程序并接受其性能影响, if 不需要处理帧更改,然后它只是稍微复杂一点:

onScroll

为了减少iOS上的性能开销,同时仍然保证我们记录滚动视图所处的任何位置,我们可以增加<ScrollView onScroll={event => { this.yOffset = event.nativeEvent.contentOffset.y }} scrollEventThrottle={16} > 并另外提供scrollEventThrottle处理程序:

onScrollEndDrag

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

<ScrollView
  onScroll={event => { 
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  onScrollEndDrag={event => { 
    this.yOffset = event.nativeEvent.contentOffset.y
  }}
  scrollEventThrottle={160}
>
是的,这太可怕了。我也不是100%肯定在同时更改滚动视图的框架和内容的大小的情况下它总能正常工作。但这是我能想到的最好的,直到this feature gets added within the framework itself,我认为这是任何人都可以做到的最好的。

答案 2 :(得分:17)

布拉德奥勒的回答是正确的。但是你只会收到一个活动。如果您需要不断更新滚动位置,您应该设置scrollEventThrottle道具,如下所示:

<ScrollView onScroll={this.handleScroll} scrollEventThrottle={16} >
  <Text>
    Be like water my friend …
  </Text>
</ScrollView>

事件处理程序:

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

请注意,您可能会遇到性能问题。相应地调整油门。 16为您提供最多的更新。 0只有一个。

答案 3 :(得分:6)

如果您希望简单地获取当前位置(例如,当按下某个按钮时)而不是在用户滚动时跟踪它,那么调用onScroll侦听器将导致性能问题。目前,最简单的获取当前滚动位置的方法是使用react-native-invoke包。这个确切的事情有一个例子,但是这个包做了很多其他事情。

在这里阅读。 https://medium.com/@talkol/invoke-any-native-api-directly-from-pure-javascript-in-react-native-1fb6afcdf57d#.68ls1sopd

答案 4 :(得分:2)

以上答案说明了如何使用不同的API onScrollonMomentumScrollEnd等获取职位;如果您想知道页面索引,可以使用偏移值进行计算。

 <ScrollView 
    pagingEnabled={true}
    onMomentumScrollEnd={this._onMomentumScrollEnd}>
    {pages}
 </ScrollView> 

  _onMomentumScrollEnd = ({ nativeEvent }: any) => {
   // the current offset, {x: number, y: number} 
   const position = nativeEvent.contentOffset; 
   // page index 
   const index = Math.round(nativeEvent.contentOffset.x / PAGE_WIDTH);

   if (index !== this.state.currentIndex) {
     // onPageDidChanged
   }
 };

enter image description here

在iOS中,ScrollView和可见区域之间的关系如下: The picture comes from https://www.objc.io/issues/3-views/scroll-view/

ref:https://www.objc.io/issues/3-views/scroll-view/

答案 5 :(得分:1)

要在原始问题请求滚动结束后获取x / y,最简单的方法可能就是:

<ScrollView
   horizontal={true}
   pagingEnabled={true}
   onMomentumScrollEnd={(event) => { 
      // scroll animation ended
      console.log(e.nativeEvent.contentOffset.x);
      console.log(e.nativeEvent.contentOffset.y);
   }}>
   ...content
</ScrollView>

答案 6 :(得分:1)

使用onScroll进入无限循环。可以使用onMomentumScrollEnd或onScrollEndDrag

答案 7 :(得分:1)

使用

require('dotenv/config') // require the dotenv/config at beginning of file
const express = require('express')
const mongoose = require('mongoose')

显示位置

<ScrollView 
 onMomentumScrollEnd={(event) => this.getscrollposition(event)} 
 scrollEventThrottle={16}>

答案 8 :(得分:0)

至于页面,我正在开发一个更高阶的组件,它基本上使用上面的方法来完成这个。当您了解初始布局和内容更改等细微之处时,实际上只需要一点时间。我不会声称“正确”地完成了它,但从某种意义上说,我会考虑使用能够仔细一致地执行此操作的组件的正确答案。

请参阅:react-native-paged-scroll-view。我会喜欢反馈意见,即使这是我做错了!

答案 9 :(得分:0)

这是最终如何从视图中实时获取当前滚动位置的方法。我正在做的是使用滚动事件监听器和scrollEventThrottle。然后,我将其作为事件传递给我,以处理我制作的滚动功能并更新道具。

 export default class Anim extends React.Component {
          constructor(props) {
             super(props);
             this.state = {
               yPos: 0,
             };
           }

        handleScroll(event){
            this.setState({
              yPos : event.nativeEvent.contentOffset.y,
            })
        }

        render() {
            return (
          <ScrollView onScroll={this.handleScroll.bind(this)} scrollEventThrottle={16} />
    )
    }
    }

答案 10 :(得分:-1)

我相信contentOffset会给你一个包含左上角滚动偏移的对象:

http://facebook.github.io/react-native/docs/scrollview.html#contentoffset

答案 11 :(得分:-3)

这适用于Android和iOS(在Android上测试):

<ScrollView ref='myScrollView'>
  <Text>Blah</Text>
</ScrollView>

...

getOffset() {
  console.log(this.refs.myScrollView.scrollProperties.offset);
}