react native 自定义下拉刷新——桥接MJRefres

作者: 我是滕先生 | 来源:发表于2016-12-11 21:27 被阅读1277次
    0、React Native 中的下拉刷新、上拉更多一直是一个很让人头疼的问题,RN中的API只能使用默认的UIRefreshControl,定制和体验上都很差,下面我通过修改系统组件的方法桥接一个原生中常用的三方库 MJRefresh ,至于上拉更多我一般使用react-native-giftedListView,可以和我这个桥接完美结合。https://github.com/XHTeng/react-native-gifted-listview

    注意:该方法的缺点是每次更新react-native 组件都需要重新修改添加一次,还没有找到好的办法能够保存修改(除非不更新RN)

    1、在React 项目中引入MJRefresh包,注意,MJRefresj.bundle 要引入到自己项目中,不要放在React项目中,不然资源无法加载。
    目录结构
    2、RCTScrollView.h 添加以下代码,并引入#import "MJRefresh.h"
    @property(nonatomic, copy) RCTDirectEventBlock onRefreshData;
    @property(nonatomic, assign) BOOL isOnPullToRefresh;
    @property (assign, nonatomic) BOOL currentRefreshingState;
    @property(nonatomic, assign) BOOL enablePullToRefresh;
    - (void)startPullToRefresh;
    - (void)stopPullToRefresh;
    

    注意,要添加在RCTScrollView的下面,不要加在了RCTEventDispatcher里面!


    RCTScrollView
    RCTEventDispatcher
    3、RCTScrollView.m 的RCTScrollView中添加以下代码,同样注意添加的位置,可以在这里修改为你需要的下拉样式
    RCTScrollView
    - (void)setEnablePullToRefresh:(BOOL)enablePullToRefresh
    {
      _enablePullToRefresh = enablePullToRefresh;
      if (enablePullToRefresh) {
        if (_scrollView.mj_header == nil) {
          MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(refreshData)];
          header.lastUpdatedTimeLabel.hidden = YES;
          header.stateLabel.hidden = YES;
          
          _scrollView.mj_header = header;
          self.currentRefreshingState = NO;
        }
      }
    }
    
    - (void)setIsOnPullToRefresh:(BOOL)isOnPullToRefresh
    {
      if (_currentRefreshingState != isOnPullToRefresh) {
        _currentRefreshingState = isOnPullToRefresh;
        if (isOnPullToRefresh) {
          [_scrollView.mj_header beginRefreshing];
          
        } else {
          [_scrollView.mj_header endRefreshing];
        }
      }
    }
    
    -(void)refreshData
    {
      _currentRefreshingState = _scrollView.mj_header.isRefreshing;
      if (_onRefreshData) {
        _onRefreshData(nil);
      }
    }
    
    - (void)startPullToRefresh
    {
      self.isOnPullToRefresh = YES;
      [_scrollView.header beginRefreshing];
      
    }
    
    - (void)stopPullToRefresh
    {
      self.isOnPullToRefresh = NO;
      [_scrollView.header endRefreshing];
      
    }
    
    4、修改RCTCustomScrollView的- (void)dockClosestSectionHeader方法实现,(RCTCustomScrollView位于RCTScrollView.m)

    找个下面这一段代码:

    if (_rctRefreshControl != nil && _rctRefreshControl.refreshing) {
        scrollTop -= _rctRefreshControl.frame.size.height;
      }
    

    在后面添加如下代码:

    if (self.header != nil && self.header.isRefreshing) {
        scrollTop -= self.header.frame.size.height;
    }
    
    5、在RCTScrollViewManager.m中增加如下代码,方便ScrollView.js中调用
    RCT_EXPORT_VIEW_PROPERTY(onRefreshData, RCTDirectEventBlock)
    RCT_EXPORT_VIEW_PROPERTY(isOnPullToRefresh, BOOL)
    RCT_EXPORT_VIEW_PROPERTY(enablePullToRefresh, BOOL)
    
    RCT_EXPORT_METHOD(stopPullToRefresh:(nonnull NSNumber *)reactTag)
    {
        [self.bridge.uiManager addUIBlock:
         ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
             
             RCTScrollView *view = viewRegistry[reactTag];
             if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
                 RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
                 return;
             }
             
             [view stopPullToRefresh];
         }];
    }
    
    RCT_EXPORT_METHOD(startPullToRefresh:(nonnull NSNumber *)reactTag)
    {
        [self.bridge.uiManager addUIBlock:
         ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
             
             RCTScrollView *view = viewRegistry[reactTag];
             if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
                 RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
                 return;
             }
             
             [view startPullToRefresh];
         }];
    }
    
    6、修改React Native自带的ScrollView.js(位于./node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js),桥接上面添加的属性、方法对应的props和函数

    增加props:

    enablePullToRefresh: PropTypes.bool,
    isOnPullToRefresh: PropTypes.bool,
    onRefreshData: PropTypes.func,
    

    增加函数:

    startPullToRefresh: function() {
      RCTScrollViewManager.startPullToRefresh(
          ReactNative.findNodeHandle(this)
      );
    },
    
    stopPullToRefresh: function() {
      RCTScrollViewManager.stopPullToRefresh(
          ReactNative.findNodeHandle(this)
      );
    },
    
    7、完成,在ListView或ScrollView中添加以下三个属性即可
    isOnPullToRefresh={this.state.isRefreshing} // 控制刷新状态,true 开始刷新,false 停止刷新
    onRefreshData={() => {  this._onRefresh();}} // 刷新回调的方法
    enablePullToRefresh={true} // 是否打开下拉刷新
    

    一般会加上系统判断,Android不需要增加修改这三个属性

    相关文章

      网友评论

      • 97bba10e85cb:在 react-native 0.44 下面不能跑,React.createClass 已被弃用

      本文标题:react native 自定义下拉刷新——桥接MJRefres

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