react native scrollView事件触发过程
2020年3月23日 • ... • ☕️ 3 min read
在使用rn的scrollView时,意外发现这玩意比单纯的html 5加个滚动条要复杂很多,特此记录。
react-native scrollview官方文档: https://reactnative.dev/docs/scrollview
触发过程
总体来说,scrollView的事件包含两种:拖动(drag)和惯性滚动(momentumScroll)。
拖动指用户手指按下、抬起的手势,对应两个方法:onScrollBeginDrag
和onScrollEndDrag
。
与html 5不同的是,用户手指抬起时,有可能会触发惯性滚动(即快速滑动结束后触发进一步滚动)。对应两个事件:onMomentumScrollBegin
和onMomentumScrollEnd
。
所以,惯性滚动触发肯定在拖动之后。
触发过程:onScrollBeginDrag -> onScroll -> onScrollEndDrag -> onMomentumScrollBegin -> onScroll -> onMomentumScrollEnd
事件和属性
scrollview包含如下5个监听事件:
onScrollBeginDrag
onScrollEndDrag
onMomentumScrollBegin
onMomentumScrollEnd
onScroll
关联的属性有:
decelerationRate
加速率,默认是normal(iOS默认就比Android灵敏一些)
取值0~1,数值越小相应滚动越不灵敏,为0时不触发惯性滚动
‘normal’,iOS是0.998, Android是0.985.
‘fast’, iOS是0.99, Android是0.9.
disableIntervalMomentum
取消在连续滑动的时候,屏幕滚动速度会越来越快。
scrollEventThrottle scroll事件的触发频率(ms),即scroll的采样率。
如何获取滚动位置
一个需求,制作一个坐标轴,横向滚动,并获取停止位置的滚动位置。
三个思路:
1、简单一些,把加速率设置为0,然后只监听onScrollEndDrag
事件即可。
<ScrollView
bounces={false}
decelerationRate={0}
onScrollEndDrag={({ nativeEvent }) => {
console.log(nativeEvent.contentOffset.x);
}}
scrollEventThrottle={400}
showsHorizontalScrollIndicator={false}
horizontal={true}
>
{ /** ... scroll content **/ }
</ScrollView>
2、或者监听onScroll,由于会根据采样率触发很多次,在做动画效果的时候会用到,但是采样率设置不当性能会受影响
<ScrollView
bounces={false}
onScrollBeginDrag={({ nativeEvent }) => {
setBeginDrag(true);
}}
onScroll={({ nativeEvent }) => {
console.log(nativeEvent.contentOffset.x);
}}
scrollEventThrottle={400}
showsHorizontalScrollIndicator={false}
horizontal={true}
>
{ /** ... scroll content **/ }
</ScrollView>
3、如果分别监听两种事件?在momentumBegin时,设置flag,由该flag决定使用哪个函数体。分别在dragEnd和momentumEnd监听里添加函数体。dragEnd中,添加setTimeout延时,在触发惯性滚动时,不使用dragEnd的位置。
另外,由于useState(set过程)也使用了浏览器事件队列,所以触发会在setTimeout之后,取不到正确的值。
let flag = false;
<ScrollView
bounces={false}
onScrollEndDrag={({ nativeEvent }) => {
setTimeout(() => {
if (!flag) {
console.log("onScrollEndDrag", nativeEvent);
// 函数体
}
}, 500);
}}
onMomentumScrollBegin={() => {
flag = true;
}}
onMomentumScrollEnd={({ nativeEvent }) => {
console.log('onMomentumScrollEnd', nativeEvent);
// 函数体
flag = false;
}}
scrollEventThrottle={400}
showsHorizontalScrollIndicator={false}
horizontal={true}
>
{ /** ... scroll content **/ }
</ScrollView>