美文网首页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