React-Native在iOS端通过MJRefresh实现自定
前言
React Native是一个跨平台的使用JavaScript编写最终生成移动端原生控件应用的开源框架。React-Native也是比较成熟的跨平台编写移动应用的解决方案。经过几年的发展,在该框架上涌现出了很多优秀的库,基于这些库我们可以更快的编写出一个功能丰富的应用。React-Native提供给了我们将原生模块和原生UI组件封装的方法,让我们可以随心拓展自己需要的原生功能,这极大丰富我们应用的功能,也为使用React-Native编写的应用提供无限的可能。
RN中实现自定义下/上拉刷新的困境
在app中,下拉刷新和上拉加载更多是一个很常见的功能。RN自然也提供了这样的控件——RefreshControl来实现ScrollView的下拉刷新。在列表组件FlatList、SectionList中直接提供onRefresh/refreshing这样的属性来实现下拉刷新,通过onEndReached来实现上拉加载更多。是的,一切看起来都很完整。只是如果我们想要实现丰富的、可高度自定义的下拉刷新和上拉加载更多时,RN提供给我们的就显得捉襟见肘了。
RN提供的下拉刷新组件中只有一个类似菊花的指示圆圈,以及圆圈底部的文本。在样式上,提供了修改菊花的颜色和大小,文字的内容和颜色的属性。菊花样式如下图所示:
下拉刷新的菊花很简洁,是苹果性冷淡的风格。
只是,在国内的绝大多数app都不会使用只有一个菊花的刷新头部样式。从国内的大厂的app来看,是丰富多彩的。面对这样的需求,RN提供给我们的就无法满足了。
如果我们想要在WebView中实现下拉刷新的功能呢?很遗憾,RN没有在WebView组件中提供可下拉刷新的属性。不过我们可以根据RN提供的现有组件组合起来——即在ScrollView中套上WebView的方法来让WebView具备下拉刷新功能。只是这样的缺陷同样明显,因为ScrollView和WebView都是可滑动组件,这就会导致有些时候,我们拖拽的是网页内容,因此不会有下拉刷新的效果。这个问题也是RN无法解决的。
如果我们想要在RN上实现自定义的刷新头部和尾部样式,那也只能通过封装原生模块的的方式来达到目的了。是的,我们确实做到了。
iOS中的MJRefresh库
如果你是iOS原生的开发者,那么你一定有听过甚至使用过这个库。MJRefresh是国人写的在国内使用得最广泛的提供下拉刷新和上拉加载更多的库之一。该库提供了高度自定义header和footer的样式和刷新过程的多种状态。同时它使用简单,一行代码即可实现刷新效果。
将MJRefresh拓展到React-Native
我们知道,RN提供给我们的刷新组件并不能很好的实现更多的自定义样式。那么我们只能通过封装原生模块来实现自定义的header和footer了。
MJRefresh是通过KVO以及iOS运行时方法为原有的iOS控件新增下拉刷新属性和方法。借鉴这一思路,与一般的组件封装思路(通过继承ScrollView原生的类来将MJRefresh封装实现下拉刷新和上拉加载更多)不同,我们也可以通过运行时方式来为RN提供的可滑动组件(比如:ScrollView、FlatList、SectionList、WebView)提供新的属性和方法来实现对MJRefresh的封装和使用。
react-native-mjrefresh-ios
通过以上的思路,我们最终完成了这一任务,并且在实际项目中得到检验和完善。最终封装成一个库:react-native-mjrefresh-ios
以下是示例效果图之一:
normal1-min.gif normal4-min.gif footer1-min.gif footer4-min.gif webview-min.gif安装
集成方法非常的简单,只需要将react-native-mjrefresh-ios下载下来,并将相应文件夹拖入到ios项目中即可完成集成。详细安装方法请看这里
用法
集成完成之后,RN的ScrollView、FlatList、SectionList、WebView组件就多出了相应的属性和回调方法来实现下拉刷新和上拉加载更多。
为了使开发者容易上手使用,react-native-mjrefresh-ios的使用方法与RN提供的组件RefreshControl的用法一致。
例如,列表组件FlatList,可以通过如下新增属性实现下拉刷新:
<FlatList
// 是否开启下拉刷新
enableMJRefresh={true}
// 指定刷新状态
mjRefreshing={this.state.refreshing}
// 拖拽刷新时,触发的回调
onMJRefresh={this.loadDataList}
// 设置header样式
mjHeaderStyle={{
// 指定属性
}}
/>
在WebView中,我们通过一行代码即可实现下拉刷新:
<WebView
source={{uri: 'https://www.baidu.com'}}
nativeConfig={{
props:{
// 是否开启下拉刷新
enableMJRefresh: true,
// 指定刷新状态
// mjRefreshing: this.state.refreshing,
// 拖拽刷新时,触发的回调
// onMJRefresh: this.reloadData,
// 设置header样式
// mjHeaderStyle: {
// // 指定属性
// }
}
}}
/>
但我们更推荐使用社区推荐的react-native-webview的WebView来加载网页,其下拉刷新功能我们也做了封装:
import { WebView } from 'react-native-webview';
// ....
<WebView
source={{uri: 'https://www.baidu.com'}}
// 是否开启下拉刷新
enableMJRefresh: true,
// 指定刷新状态
// mjRefreshing: this.state.refreshing,
// 下拉刷新触发时,的回调
// onMJRefresh: this.loadData,
// mjHeaderStyle: {
// // 指定样式属性
// }
/>
对于上拉加载更多,我们也提供了相应的属性和回调方法:
例如:
<FlatList
// 是否开启上拉加载更多
enableMJLoadMore={this.state.enableLoadMore}
// 是否正在加载更多
mjLoadingMore={this.state.loadingMore}
// 是否已经加载全部
mjLoadAll={this.state.isLoadAll}
// 触发加载更多的回调
onMJLoadMore={this.loadMoreData}
// footer的样式
mjFooterStyle={{
// 设置属性
}}
/>
自定义header和footer样式
react-native-mjrefresh-ios库提供了非常多的属性来自定义刷新组件的样式。通过指定mjHeaderStyle和mjFooterStyle即可实现,具体可用的属性可以查看这里
写在最后
React-Native是被开发者广泛使用的用于编写跨平台移动端应用的框架之一。它尽管目前仍存在些不完善的地方,但它也仍然在不断地迭代中。同时社区开发者也不断贡献自己的库,使这个生态越来越完善和健壮。
react-native-mjrefresh-ios弥补了RN在iOS端无法自定义上/下拉刷新的缺陷,也提供了新的上/下拉刷新的方法。当然react-native-mjrefresh-ios也存在着他的不足。RN作为跨平台的解决方案,目前这个库只提供了iOS端的解决方案,并没有提供安卓端的解决方案。