react native listview上拉加载更多下拉刷新兼容ios 安卓

   无论是安卓还是ios中,上拉加载下拉刷新的列表组件都是必不可少而且已经有足够优秀的第三方控件可以快速集成使用。但是在React Native中,当你想要实现安卓或者ios的上拉刷新或者下拉加载时,你会尴尬的发现,似乎并没有那么让人满意的实现。下面我将介绍一种我的方式,在安卓中通过ListView+ RefreshControl+PanResponder,在ios中通过ListView+ RefreshControl实现上拉加载下拉刷新的效果。在最后,只需要将两个文件命名为xxx.android.jsxxx.ios.js,APP会自动根据平台加载相应的js文件。

       首先介绍ios中的实现方式,比较简单。下拉加载的实现React Native中提供了RefreshControl的方式,而上拉通过onEndReached()来实现。先看下官网对onEndReached的介绍:

onEndReached function :当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。

onEndReachedThreshold number :调用onEndReached之前的临界值,单位是像素。

       也就是当设置了onEndReachedThreshold number的属性,上拉到距离底部number距离的时候,就会触发onEndReached方法。你可能会疑惑,既然如此为什么ios与安卓中的实现方式不一样呢?就是因为两个平台对于可滑动组件滑动到底部的处理方式不相同onEndReachedThreshold在安卓中为正值,但是在ios中可以是负数。在ios中,可滑动控件拉倒底部后仍然可以上拉一部分距离,而在安卓中拉倒底部就不能在上拉了。你可以拿苹果手机和安卓手机试试。而这就导致了在ios中,我们将onEndReachedThreshold设置一个恰当的负数,即便拉到底部,每次上拉我们都可以完美的实现上拉到底的时候加载更多的处理;但是安卓中上拉到底部满足触发条件时候,拉到底部,触发一次,当界面仍然在底部的时候,你就会尴尬的发现不会触发onEndReached方法,因为这时候距离底部的距离为0onEndReachedThreshold在安卓中大于0),不满足触发条件不会再次触发,因此这种方式在安卓中是不完全适用的。所以我们在安卓中使用手势识别的方式。好了,下面继续介绍ios的实现方式。

     代码是最直接的,先上代码,我会分析讲解代码。

 constructor(props) {

    super(props);

    this.pullUpToLoad = this.pullUpToLoad.bind(this);

    this.state = {

      nomore: true,

      init: '0',

      dataSource: _dataSource.cloneWithRows(alarmArray1),

      foot: 0, // 控制foot0:隐藏foot  1:已加载完成   2:显示加载中

      isRefreshing: false,

      deleteCell: false

    };

  }

 

  <ListView

          dataSource={this.state.dataSource}

          renderRow={this.renderRow.bind(this) }

          onEndReached={this.pullUpToLoad.bind(this)}

          renderFooter ={this._renderFooter.bind(this) }

          onEndReachedThreshold={ -50 }

          removeClippedSubviews={false}

          refreshControl={

            <RefreshControl

              refreshing={this.state.isRefreshing}

              onRefresh={this.loadMore.bind(this) }

              colors={['#ff0000', '#00ff00', '#0000ff', '#3ad564']}

              progressBackgroundColor="#ffffff"

            />

          }

          />

   下拉刷新简单,只需要配置好RefreshControl,默认isRefreshingfalse,当下拉时会自动触发RefreshControlUI显示,这部分不需要你来操心。

    ListView支持添加头尾,因为下拉刷新我们使用RefreshControl自带的效果,因此我们只需要加个renderFooter实现上拉加载的UI处理。如代码所示,onEndReachedThreshold={ -20 },当上拉ListView距离底部20个单位距离的时候会触发onEndReached={this.pullUpToLoad.bind(this)},可以在pullUpToLoad中,当滑动到底部的时候通过setState触发renderFooter绘制“加载更多”的UI,至于renderFooterUI的具体实现要结合需求,我只是讲个基本的实现和思路,如何结合你的项目更好的实现要请你自己多动脑了。

 //上拉到底部

  pullUpToLoad() {

  //通过setState设置nomore属性控制UI的展现

  }

   //上拉到底UI

  _renderFooter() {

    if (this.state.nomore) {

      return null;

    }

    return (

      <View style={{alignItems: 'center' }}>

        <ActivityIndicator />

        <Text >数据加载中..</Text>

      </View>

    );

  }      

 这样,在ios中下拉刷新上拉加载就完成了。

下面是安卓中的实现。

    <View   style={{ height: height - 50 }} {...this.panResponder.panHandlers}>

            <ListView

              dataSource={this.state.dataSource}

              renderRow={this.renderRow.bind(this) }

               //onEndReached={this.pullUpToLoad.bind(this)}

              renderFooter ={this._renderFooter.bind(this) }

              onEndReachedThreshold={10}

              removeClippedSubviews={false}

              refreshControl={

                <RefreshControl

                  refreshing={this.state.isRefreshing}

                  onRefresh={this.loadMore.bind(this) }

                  colors={['#ff0000', '#00ff00', '#0000ff', '#3ad564']}

                  progressBackgroundColor="#ffffff"

                  />

              }

              />

          </View>

安卓中实现方式 RefreshControl+PanResponder,上面讲了,onEndReached在安卓中不好用,所以使用手势识别,识别上拉的距离,上拉距离满足一定条件且ListView已经滑动到底部,我们就可以当做上拉加载更多的触发条件。

首先引入手势识别,

  componentWillMount() {

//此处省略无关部分代码

    this.panResponder = PanResponder.create({

      // 要求可以响应触摸事件

      onStartShouldSetPanResponder: (evt, gestureState) => {

        return true

      },

      onStartShouldSetPanResponderCapture: (evt, gestureState) => {

        return true;

      },

      onMoveShouldSetPanResponder: (evt, gestureState) => {

        return true;

      },

      onMoveShouldSetPanResponderCapture: (evt, gestureState) => {

        return true;

      },

      // 释放的事件回调

      onPanResponderRelease: (evt, gestureState) => {

        this.onEnd(evt, gestureState);

      },

      onPanResponderTerminate: (evt, gestureState) => {

        this.onEnd(evt, gestureState);

      },

    });

}

  onEnd(evt, gestureState) {

    if (gestureState.dy < -20) {

      if (this.state.isRefreshing == false) {

        this.pullUpToLoad();

      }

    }  

  }

在监测到上拉距离达到20单位,且不在刷新状态,就可以触发上拉加载更多了,UIios一样也是

//上拉到底部

  pullUpToLoad() {

  //通过setState设置nomore属性控制UI的展现

  }

   //上拉到底UI

  _renderFooter() {

    if (this.state.nomore) {

      return null;

    }

    return (

      <View style={{alignItems: 'center' }}>

        <ActivityIndicator />

        <Text >数据加载中..</Text>

      </View>

    );

  }      

这两个方法来实现。


下拉刷新与ios中也是一样的。下面是效果图:

react native listview上拉加载更多下拉刷新兼容ios 安卓

 react native listview上拉加载更多下拉刷新兼容ios 安卓