免责声明:以下内容主要是我自己在React Native 0.50中进行实验的结果。该ScrollView
文档当前缺少许多下面介绍的信息。例如onScrollEndDrag
完全没有文件记录。由于此处的所有内容都依赖于未记录的行为,因此,我不能保证此信息将在一年甚至一个月后保持正确。
同样,下面的所有内容都假定为纯垂直滚动视图,我们感兴趣的是y偏移量;如果需要的话,希望将其转换为x偏移量对于读者来说是一个容易的练习。
在各种事件处理ScrollView
采取event
让你通过当前滚动位置event.nativeEvent.contentOffset.y
。其中一些处理程序在Android和iOS之间的行为略有不同,如下所述。
在Android上
在用户滚动时触发每个帧,在用户释放滚动视图后滑动视图时在每个帧上触发,在滚动视图静止时在最后一个帧上触发,并且在滚动视图的偏移因其帧而改变时触发变化(例如由于从横向旋转到纵向)。
在iOS上
在用户拖动时或滚动视图滑动时触发,以决定的某个频率,scrollEventThrottle
每帧最多至一次scrollEventThrottle={16}
。如果用户在有足够的动量可以滑动时释放滚动视图,则onScroll
在滑动后静止时,处理程序也会触发。但是,如果用户在静止状态下拖动然后释放滚动视图,onScroll
则除非已设置为触发滚动的每一帧,否则不能保证为最终位置触发。scrollEventThrottle
onScroll
scrollEventThrottle={16}
通过设置较大的数字可以降低设置的性能成本。但是,这onScroll
将不会触发所有帧。
滑动后滚动视图停止时触发。如果用户在滚动视图静止时释放滚动视图而不会滑动,则根本不会触发。
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}
>
但是,如果我们要处理框架更改(例如,因为我们允许设备旋转,更改滚动视图框架的可用高度)和/或内容更改,则我们必须另外实现两者onContentSizeChange
并onLayout
跟踪两者的高度滚动视图的框架及其内容,从而连续计算最大可能的偏移量,并推断何时由于框架或内容大小的变化而自动减少了偏移量:
<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%肯定会在您同时更改滚动视图的框架大小和内容的情况下始终正常工作。但这是我能想到的最好的方法,并且直到在框架本身中添加此功能之前,我认为这是任何人都能做到的最好方法。