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下拉刷新(二):修改RN代码,集成iOS原生下拉刷新_第1张图片
果然原生效果比RN体验强太多了。

你可能感兴趣的:(React-Native,iOS开发)