在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> 

尝试。

 <ScrollView onScroll={this.handleScroll} /> 

接着:

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

Brad Oyler的回答是正确的。 但是你只会收到一个事件。 如果你需要获得滚动位置的不断更新,你应该设置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只有一个。

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

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

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

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

这应该适用于Android和iOS(在Android上testing):

 <ScrollView ref='myScrollView'> <Text>Blah</Text> </ScrollView> ... getOffset() { console.log(this.refs.myScrollView.scrollProperties.offset); } 

至于页面,我正在使用一个更高阶的组件,基本上使用上述方法来做到这一点。 实际上,只需要一点时间,就可以了解初始布局和内容更改等细微之处。 我不会声称做了“正确的”,但从某种意义上说,我会考虑使用正确的答案来使用这个小心谨慎的组件。

请参阅: react-native-paged-scroll-view 。 会爱反馈,即使这是我所做的一切都是错的!

免责声明:接下来的主要是我自己在React Native 0.50中的实验结果。 ScrollView文档目前缺less大量以下信息; 例如onScrollEndDrag完全没有logging。 由于这里的一切都依赖于无证的行为,所以我不能保证这些信息在一年甚至一个月后仍然是正确的。

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


一个ScrollView上的各种事件处理程序会接收一个event并通过event.nativeEvent.contentOffset.y获取当前的滚动位置。 这些处理程序中的一些在Android和iOS之间的行为稍有不同,如下所述。

onScroll

在Android上

当用户滚动时触发每一帧,在用户释放滚动视图的同时滚动视图在每帧上滑动,当滚动视图停止时在最后一帧上触发每一帧,并且每当滚动视图的偏移由于其帧而改变改变(例如由于从风景到肖像的旋转)。

在iOS上

在用户拖动时或滚动视图滑动时scrollEventThrottle ,按scrollEventThrottle确定的某个频率进行scrollEventThrottle ,当scrollEventThrottle={16}时,每个框架最多scrollEventThrottle一次。 如果用户在有足够动量滑动的时候释放滚动视图, onScroll处理程序在滑动后还会触发。 但是,如果用户在静止时拖动并释放滚动视图, 则不保证onScroll会触发最终位置,除非已设置onScroll ,以使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} > 

为了减lessiOS上的性能开销,同时保证我们logging滚动视图的位置,我们可以增加scrollEventThrottle并另外提供一个onScrollEndDrag处理函数:

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

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

 <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%肯定的是,在同时更改滚动视图的框架和内容的大小的情况下,它总能正常工作。 但是这是我能想到的最好的,直到这个特性被添加到框架本身 ,我认为这是最好的,任何人都可以做。

为了得到滚动结束后的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>