react native scrollView事件触发过程

2020年3月23日 ... ☕️ 3 min read

在使用rn的scrollView时,意外发现这玩意比单纯的html 5加个滚动条要复杂很多,特此记录。

react-native scrollview官方文档: https://reactnative.dev/docs/scrollview

触发过程

总体来说,scrollView的事件包含两种:拖动(drag)和惯性滚动(momentumScroll)。

拖动指用户手指按下、抬起的手势,对应两个方法:onScrollBeginDragonScrollEndDrag

与html 5不同的是,用户手指抬起时,有可能会触发惯性滚动(即快速滑动结束后触发进一步滚动)。对应两个事件:onMomentumScrollBeginonMomentumScrollEnd

所以,惯性滚动触发肯定在拖动之后。

触发过程: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>

#react#react-native

SideEffect is a blog for front-end web development.
Code by Axiu / rss