在前两篇文章中已经介绍了如何实现一个支持下拉刷新和上拉加载更多的列表以及如何使用Redux进行单向数据流,那这篇就会介绍下最后一个模块筛选功能的开发即React Native与原生iOS的通信。
开始之前,还是先看一下最终实现的效果
关于如何进行React Native与原生iOS的通信,在官网中有很明确的教程,这里我就不细说了。我分享的主要是如何利用那些接口实现这样的一个效果。
在项目中,筛选条和对应的子菜单都是使用原生代码实现的,而列表使用js代码实现的。我们要做的就是将这些原生页面通过桥接的方式添加到js页面上。
桥接实现在FHTFilterMenuManager
这个类中,其实现如下:
- 原生实现
1 | // .h |
- JS实现
1 | import React, { Component } from 'react'; |
- JS调用
1 | <SearchFilterMenu |
创建ViewManager
FHTFilterMenuManager
是继承自RCTViewManager
,每一个原生UI都需要被一个RCTViewManager
的子类来创建和管理。在程序运行过程中,RCTViewManager
会创建原生UI并把视图提供给RCTUIManager
,RCTUIManager
则反过来委托RCTViewManager
在需要的时候去设置和更新视图的属性。这里有一个注意点:ViewManager的命名格式是原生组件名字+Manager。
在ViewManager中最重要的是必须实现- (UIView *)view
,用来返回你想要桥接的原生UI。
从React Native传递属性到原生组件
我们知道属性是最简单的跨组件通信,如果RN组件接受到一个属性的时候,可以通过RCT_EXPORT_VIEW_PROPERTY
和RCT_CUSTOM_VIEW_PROPERTY
的方式传递给原生组件。
RCT_EXPORT_VIEW_PROPERTY
可以将原生组件自带的属性暴露给JS。所以在FHTFilterMenuManager
中,我暴露三个自带的属性给JS,分别是
1 | // 点击确定按钮执行网络请求的block |
这里我使用了分类的方式对原生组件的属性进行拓展,因为在项目中,我并不希望原生组件有太多RN桥接相关的代码,所以使用分类拓展,这样也可以对代码进行解耦。
这里有一个注意点:如果自带的属性是block类型的话,属性名必须以on开头。
RCT_CUSTOM_VIEW_PROPERTY
可以让我们添加一些更为复杂的属性。由于cityId
和subwayData
是FilterMenuGeographicController
这个子菜单才需要的,如果把它们设置为FHTFilterMenu
的属性并不合适,而FilterMenuGeographicController
我们并没有暴露给JS,所以我们可以使用RCT_CUSTOM_VIEW_PROPERTY
对没有暴露给JS的对象进行属性传递。
1 | RCT_CUSTOM_VIEW_PROPERTY(cityId, NSString, FHTFilterMenu) { |
React Native调用原生组件的方法
RCT_EXPORT_METHOD
用来提供原生方法给JS调用。RCT_EXPORT_METHOD(showFilterMenuOnView:(nonnull NSNumber *)containerTag filterMenuTag:(nonnull NSNumber *)filterMenuTag)
用来实现将子菜单添加到SearchHousePage
,其实现如下:
1 | RCT_EXPORT_METHOD(showFilterMenuOnView:(nonnull NSNumber *)containerTag filterMenuTag:(nonnull NSNumber *)filterMenuTag) { |
其中containerTag
代码用来表示SearchHousePage
,filterMenuTag
则表示筛选条。这里有一个注意点:不能使用self.view的方式因为会创建出一个新的FHTFilterMenu对象,更不能在- (UIView *)view
中使用一个指针对创建出来的View进行引用,如果你的组件在多个页面都用使用的话,是会出问题的。
另外,由于iOS的UI操作是要放在主线程完成的,所以最好methodQueue
指定为主线程。
结尾
到这里整个SearchHousePage
页面的开发已经完成,如果需要查看完整代码的话,在代码传送门–NNHybrid中。