美文网首页React Native开发经验集React Native开发
低版本React Native中ListView和ScrollV

低版本React Native中ListView和ScrollV

作者: 恐怕是小珠桃子 | 来源:发表于2018-10-16 17:19 被阅读156次

我们日常开发的时候,经常会遇到上拉加载更多的需求,原因很简单,数据量大的时候分批次加载可提高加载效率,为用户省点流量和时间。

最近在使用RN0.35实现上拉加载时,遇到了一些坑,总结之后决定分享给大家。希望能给正在使用低版本RN的你提供一些帮助。

ListView实现上拉加载

1. 实现简单的上拉加载

ListView中提供了onEndReached方法,触发时机为当所有行都已渲染且列表已滚动到底部。如此说来,在ListView中实现上拉加载直接使用onEndReached就可以完成,如下(在loadMoreData中完成上拉加载功能):

<ListView onEndReached={this.loadMoreData}/>
2. 坑来了【划重点】

上述过程已经实现了上拉加载,但你会发现存在一个问题:当列表内容小于列表高度时,onEndReached被频繁触发,为什么呢?我们来一起看下RN的源码(ListView.js中的_getDistanceFromEnd_maybeCallOnEndReached方法):

_maybeCallOnEndReached: function(event?: Object) {
  if(... // 省略
    && this._getDistanceFromEnd(this.scrollProperties) < this.props.onEndReachedThreshold
    ... // 省略) {
    this.props.onEndReached(event);
  }
},

_getDistanceFromEnd:function _getDistanceFromEnd(scrollProperties){
  return scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset;
},

从上述代码中,我们提取到,onEndReached被触发的重要条件是:

contentLength - visibleLength - offset < onEndReachedThreshold

其中contentLength是列表内容的长度,visibleLength是列表的高,offset是滑动的距离,onEndReachedThreshold是默认值为1000的可控常量。回到之前的问题,当列表内容小于列表高度时(contentLength < visibleLength),offset一定是0(因为这会儿滑不动。。)。也就是此时说onEndReached被触发的条件是:

  • onEndReachedThreshold为负数,小于0且大于contentLength - visibleLength

那么onEndReachedThreshold的含义是什么?可以设置为负数吗?
答案是当然不行!设置onEndReachedThreshold的原因是在我们实现上拉加载的时候,如果到了底部再加载,用户看起来会比较慢,设置onEndReachedThreshold可以使得onEndReached提前触发,(距离列表底部onEndReachedThresholdpixel时触发。可自行画图理解其中关系

到这你可能已经明白了,我们只需要控制仅当内容大于或等于列表高度时(contentLength >= visibleLength),触发上拉加载,如下:

handleEndReached = () => { 
  const { contentLength, visibleLength } = this.listView.scrollProperties;
    if (contentLength >= visibleLength) {
      this.loadMoreData();
    }
}

<ListView
  ref={(component) => { this.listView = component; }}
  onEndReached={this.handleEndReached}
  onEndReachedThreshold={20}
/>

ScrollView实现上拉加载

细心的你一定已经发现,ScrollView并没有提供onEndReached方法,因为ScrollView是不会限制长度的,内容是无限长的。如果因为业务原因必须使用ScrollView,又需要上拉加载,怎么办呢?

ScrollView提供了onScrollEndDrag方法,onScrollEndDrag会在每次结束滚动后触发,我们要做的就是,在这个时机中,判断是否滑动到了底部,如果到了底部,则上拉加载。方法和ListView类似,我们依然可以找到内容高度,列表高度,以及滑动的距离来判断是否需要加载。如下:

handleScrollEnd = (event) => {
    const contentHeight = event.nativeEvent.contentSize.height;
    const scrollViewHeight = event.nativeEvent.layoutMeasurement.height;
    const scrollOffset = event.nativeEvent.contentOffset.y;

    const isEndReached = scrollOffset + scrollViewHeight >= contentHeight; // 是否滑动到底部
    const isContentFillPage = contentHeight >= scrollViewHeight; // 内容高度是否大于列表高度

    if (isContentFillPage && isEndReached) {
      this.loadMoreData();
    }
  };
  
<ScrollView
    onScrollEndDrag={this.handleScrollEnd}
/>

如果你有别的问题或对本文存在疑问,评论区等你哈

相关文章

网友评论

  • 星辰大海_王:高版本有问题吗
    恐怕是小珠桃子:不知道你具体使用的rn哪个版本。一个小建议:如果有问题最好说明具体环境;文中提到了问题出现的原因是源码的实现方式,并贴出了源码,如果你想知道某版本有无此问题,建议查看该版本源码的实现是否如上文。:blush:

本文标题:低版本React Native中ListView和ScrollV

本文链接:https://www.haomeiwen.com/subject/dbwhzftx.html