RN下拉刷新(二):修改RN代碼,集成iOS原生下拉刷新

在之前我已經用JavaScript實現了下拉刷新,詳見RN下拉刷新(一):使用JavaScript實現,但是還遺留了一個問題無法解決,該篇就來解決該問題

使用Javascript實現的下拉刷新,在列表先上滑再下滑的情況下下拉刷新無法使用,必須鬆開手指後再次滑動纔可以正常下拉刷新,我本來想着這樣算了,好不容易實現了一個下拉刷新。但是大佬非覺得不行,所以最終還是通過修改RN的源代碼集成原生的下拉刷新。原生的下拉刷新是繼承自MJRefreshHeader,修改起來也很簡單,改動也不大。

RN的源代碼位於 /項目目錄/RN/node_modules/react-native/React/Views 目錄下。

實現步驟如下:

  1. #import “RCTScrollableProtocol.h” 在自己的下拉刷新控件中導入該頭文件,然後實現RCTCustomRefreshContolProtocol協議,並添加屬性:
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
  1. 根據自己的下拉刷新控件實現setRefreshing方法,因爲MJRefresh在內部實現了絕大部分,所以下拉刷新的時候不需要我做處理,我只需要在refreshing狀態變爲false的時候停止刷新即可,所以我的實現如下:
- (void)setRefreshing:(BOOL)refreshing
{
    if(self.isRefreshing && refreshing == NO) {
        [self endRefreshing];
    }
    
    return ;
}
  1. 打開RCTRefreshControlManager.m文件,修改view方法,將下拉刷新控件替換成自己的控件,如下所示:
@implementation RCTRefreshControlManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
  return [[RCTRefreshGifHeader alloc] init];
}

RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(refreshStyle, NSInteger)

@end

其中RCTRefreshGifHeader是我自己的下拉刷新控件,refreshStyle是我自己導出的樣式屬性,因爲我們的下拉刷新有兩種樣式,黑色和白色,該屬性用於在RN指定下拉刷新的樣式。導出屬性後需要在下拉刷新控件中添加setRefreshStyle方法,否則報錯。

  1. 打開RCTScrollView.m文件,在insertReactSubview方法中,將類型替換成自己的下拉刷新控件,如下所示:
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
{
  [super insertReactSubview:view atIndex:atIndex];
#if !TARGET_OS_TV
  if ([view conformsToProtocol:@protocol(RCTCustomRefreshContolProtocol)]) {
    [_scrollView setCustomRefreshControl:(UIView<RCTCustomRefreshContolProtocol> *)view];
    if (![view isKindOfClass:[RCTRefreshGifHeader class]]
        && [view conformsToProtocol:@protocol(UIScrollViewDelegate)]) {
      [self addScrollListener:(UIView<UIScrollViewDelegate> *)view];
    }
  } else
#endif
  1. 在集成過程中發現佈局異常,添加進去之後並沒有重新佈局,所以在RCTScrollView.m文件中的layoutsubview中我添加了一句setNeedsLayout,如下所示:
- (void)layoutSubviews
{
  [super layoutSubviews];
  RCTAssert(self.subviews.count == 1, @"we should only have exactly one subview");
  RCTAssert([self.subviews lastObject] == _scrollView, @"our only subview should be a scrollview");

#if !TARGET_OS_TV
  // Adjust the refresh control frame if the scrollview layout changes.
  UIView<RCTCustomRefreshContolProtocol> *refreshControl = _scrollView.customRefreshControl;
  if (refreshControl && refreshControl.isRefreshing) {
    refreshControl.frame = (CGRect){_scrollView.contentOffset, {_scrollView.frame.size.width, refreshControl.frame.size.height}};
  }else {
      [refreshControl setNeedsLayout];
  }
#endif

  [self updateClippedSubviews];
}

其他的部分則需要根據自己的下拉刷新做不同的修改,在此也不過多講述,最終效果如下:

果然原生效果比RN體驗強太多了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章