列表视图在app中是非常常见的,目前React Native比较严重的性能问题集中在FlatList大列表等地方,以下通过js层的优化,甚至原生层的优化封装,使性能媲美原生。

FlatList

React Native 0.43版本推出FlatList替代ListView,FlatList实现继承自VirtualizedList,底层的VirtualizedList提供更高的灵活性,但使用便捷性不如FlatList,如无特殊需求无法满足直接使用FlatList。VirtualizedList实现继承自ScrollView,所以FlatList继承了VirtualizedList和ScrollView全部的props,在查阅相关文档时,如在FlatList中找不到相应的prop或者方法可以使用另外两个组件的。React Native的FlatList与android listview、ios uitableview相似,将屏幕外的视图组件回收,达到高性能的目的。

用法

以下实例代码均使用typescript

基本使用

<FlatList<number>// 数据数组data={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}// keykeyExtractor={(item, index) => index.toString()}// item渲染renderItem={({item: num}) => (<Text>{num}</Text>)}
/>
复制代码

常用props

extraData

有除data以外的数据用在列表中,在此属性中指定,否则界面很可能不会刷新

horizontal

设置为 true 则变为水平布局模式

inverted

翻转滚动方向,多用于聊天列表之类反向展示数据

numColumns

指定一列显示多少个item

常用方法

scrollToEnd

滑动到视图底部

scrollToIndex

滑动到指定位置

scrollToOffset

滑动到指定像素

上拉加载

<FlatList// 上拉回调onEndReached={() => console.log('上拉加载')}// 滑动到最后视图内容比例,设置为0-1,例如0.5则表示滑到最后一个视图一半开始回调onEndReachedThreshold={0.1}
/>
复制代码

下拉刷新

<FlatList// true显示刷新组件refreshing={this.state.refreshing}// 下拉回调onRefresh=(async () => {this.setState({refreshing: true});await 耗时操作this.setState({refreshing: false});});
/>
复制代码

滑动事件

onTouchStart

手指按下开始滑动,调用一次,用于监听交互开始

onTouchMove

手指滑动,调用多次

onTouchEnd

手指松开,调用一次,开始惯性滚动,用于监听交互结束

onMomentumScrollBegin

惯性滚动开始,调用一次,用于监听滑动惯性动画开始

onMomentumScrollEnd

惯性滚动结束,调用一次,用于监听滑动惯性动画结束

onScroll

滑动中,调用多次,用于监听滑动位置

onScrollBeginDrag

开始滑动,调用一次,用于监听滑动开始

onScrollEndDrag

滑动结束,调用一次,用于监听滑动结束

分页

用以开发简单轮播视图,分页滑动查看内容等

// 当前视图索引
private index = 0;
// 必须与this绑定,否则抛出异常
private viewabilityConfig = {viewAreaCoveragePercentThreshold: 100};handleViewableItemsChanged = (info: { viewableItems: Array<ViewToken>; changed: Array<ViewToken>}) => {// index为当前可见视图在view的索引this.index = info.changed[0].index!;
}<FlatList// 每次滑动后一个item停留在整个视图pagingEnabled={true}// 可见视图设置,1-100,50表示一半可见时回调,100表示全部可见时回调viewabilityConfig={this.viewabilityConfig}// 可见视图变更回调onViewableItemsChanged={this.handleViewableItemsChanged}// onViewableItemsChanged会多次回调,监听惯性滑动结束判断分页滑动结束,如需要实时判断视图索引显示,则直接使用onViewableItemsChangedonMomentumScrollEnd={() => console.log('滑动至', this.index)}
/>
复制代码

优化

removeClippedSubviews

移除在屏幕外组件,默认为true,对性能有最大的影响,不要修改为false

windowSize

保持视图个数,即在屏幕外也不移除,默认值为11,在高耗性能组件中,可以适当设置小的值,在会快速滑动的视图中,设置大的值如300,避免快速滑动后当前视图还没有渲染出现空白。

getItemLayout

获取高度,如视图高度固定,设置该属性可以大大改善性能,避免了渲染过程中每一次都需要重新计算视图高度。

getItemLayout={(data, index) => ({length: height, offset: height * index, index})}

key

合理设置key提高react对组件的复用,能很大的优化性能,在组件移出屏幕外,被回收后复用。

原生优化

在要求极高的列表视图中,数据达上千甚至上万,在部分情况FlatList已经无法满足,特别是android设备。以下介绍如何直接使用原生android RecyclerView视图来完成高要求的列表视图。

原生视图代码

public class MyFlatListManager extends SimpleViewManager<MyFlatListManager.MyRecyclerView> {// 自定义RecyclerViewpublic static class MyRecyclerView extends RecyclerView {// 数据列表public List<Data> list = new ArrayList<>();// 适配器public MyAdapter myAdapter;// 布局管理器public LinearLayoutManager mLayoutManager;public MyRecyclerView(Context context) {super(context);myAdapter = new MyAdapter(this, list);// 设置为垂直方向mLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);setLayoutManager(mLayoutManager);// 固定高度避免重新测量,提高性能setHasFixedSize(true);// 禁止数据变更时动画,避免闪烁setItemAnimator(null);setAdapter(myAdapter);}@Overridepublic void requestLayout() {super.requestLayout();// react native android根视图requestLayout为空函数,避免加入新视图无法显示或者高度宽度不正确,手动执行测量post(measureAndLayout);}public final Runnable measureAndLayout = new Runnable() {@Overridepublic void run() {measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));Log.d(TAG, "measureAndLayout");layout(getLeft(), getTop(), getRight(), getBottom());}};}private static class MyViewHolder extends RecyclerView.ViewHolder {public MyViewHolder(View itemView) {super(itemView);}}private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {private List<MyViewHolder> holders;private List<Data> list;private MyRecyclerView recyclerView;public MyAdapter(MyRecyclerView recyclerView, List<VideoInfo> list) {this.list = list;this.holders = new ArrayList<>();this.recyclerView = recyclerView;}// 视图创建@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_row, parent, false);// 手动重新设置高度,match parent      itemView.getLayoutParams().height = parent.getHeight();itemView.getLayoutParams().width = parent.getWidth();return new MyViewHolder(itemView);}@Overridepublic void onBindViewHolder(final MyViewHolder holder, int position) {Data data = list.get(position);
//      Log.i(TAG, "setTag " + position);holder.itemView.setTag(position);// 绑定视图数据}@Overridepublic int getItemCount() {return list.size();}}private static final String TAG = "MyFlatListViewManager";@Overridepublic String getName() {return "MyFlatListViewManager";}@Overrideprotected MyRecyclerView createViewInstance(final ThemedReactContext reactContext) {return new MyRecyclerView(reactContext);}@Nullable@Overridepublic Map<String, Integer> getCommandsMap() {Map<String, Integer> commandsMap = new HashMap<>();commandsMap.put("addData", 1);return commandsMap;}@Overridepublic void receiveCommand(MyRecyclerView root, int commandId, @Nullable ReadableArray args) {MyAdapter myAdapter = (MyAdapter) root.getAdapter();switch (commandId) {case 1:if (args == null) return;Log.i(TAG, "addData size: " + args.size());Integer position = root.list.size();for (int i = 0; i < args.size(); i++) {// 初始化值,getData为从map中获取data的函数,自行根据结构实现Data data = getData(args.getMap(i));Log.i(TAG, "add data " + data);root.list.add(data);}Log.i(TAG, "addDatas old position " + position + " size " + args.size());// 通知变更myAdapter.notifyItemRangeInserted(position, args.size());break;}}
}复制代码

需要注意的有几个地方

  • setHasFixedSize 如果视图高度固定,设置固定高度能提高性能
  • setItemAnimator 动画可能会导致在加载图片等的时候闪烁
  • requestLayout 必须重新手动触发测量视图,在android中这部分机制被react native屏蔽
  • onCreateViewHolder 必须手动设定itemView高度和宽度

react反模式

在原生组件和js层进行props传递,如数据量太大,使用props直接传递已经不合适,数据可能已经达到几m甚至更大。react的props模式已经不再适合这样的场景,在web中也是,大量的数据每一次单个数据的变更都全部重新传递,会导致严重的性能问题。在这种情况下,使用组件ref调用函数来一个一个添加或者一个一个移除相关数组这些大的对象,会很好的提升性能。在android的代码中,不再使用prop传递FlatList的data,而是使用add的方法来添加,然后在js层再进行一层的原生组件封装,让使用与其他组件一致。

React Native列表视图FlatList使用优化实践指南相关推荐

  1. 基于 React Native 的 58 同城 App 开发实践

    作者简介: 彭飞,58 同城 iOS 客户端架构师.专注于新技术的研发,主要负责 App 端组件化架构以及性能优化,并已推广 React Native 在 58 同城 App 中业务场景的应用.在 M ...

  2. 大道至简——React Native在直播应用中的实践

    声明:本文来自「七牛云主办的架构师实践日--亿级移动应用架构最佳实践」的演讲内容整理.PPT.速记和现场演讲视频等参见"七牛架构师实践日"官网. 嘉宾:卜赫,七牛云布道师. 责编: ...

  3. GitChat · 移动开发 | 征服React Native—列表组件

    GitChat 作者:Li Luo 原文:征服React Native-列表组件 关注公众号:GitChat 技术杂谈,一本正经的讲技术 前言 移动应用往往受限于屏幕大小,而数据内容长度的不确定性,在 ...

  4. React Native在美团外卖客户端的实践

    MRN简介 MRN(Meituan React Native) 是基于开源的React Native框架改造并完善而成的一套动态化方案,在开发体验上基本能与原生RN保持一致,同时从业务需求的角度满足从 ...

  5. React Native组件之FlatList

    在过去的一年中React Native经历了从v0.40到v0.52的十几次的版本迭代,可以看到,特别是0.50之后,React Native的组件库在不断地壮大,React Native也正在越来越 ...

  6. React Native学习五- FlatList

    高性能的简单列表组件,支持下面这些常用的功能: 完全跨平台. 支持水平布局模式. 行组件显示或隐藏时可配置回调事件. 支持单独的头部组件. 支持单独的尾部组件. 支持自定义行间分隔线. 支持下拉刷新. ...

  7. React Native 项目简单整理-组件优化

    2019独角兽企业重金招聘Python工程师标准>>> 断断续续敲了一天,记录一下没有优化的分类的代码,App.js 里的代码 /*** Sample React Native Ap ...

  8. oracle性能优化求生指南_Vue项目性能优化--实践指南,网上最全最详细

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 第一时间与你相约 每日英文 Some happened could not forget, even forget also o ...

  9. 美图Android编译速度优化实践指南

    分享嘉宾:张仙华 美图 资深开发工程师 分享嘉宾:张仙华,美图秀秀android团队资深研发工程师,负责编译加速.性能优化.架构设计等公共基础相关工作 导读:本文的主题是美图秀秀的Android编译速 ...

最新文章

  1. 天池算法赛:数据挖掘经典赛事!DCIC 2020 数字中国创新大赛启动!
  2. 华为NPU卡ubuntu(无网络连接情况)驱动安装记录
  3. 社交网络图挖掘4--三角形计数问题
  4. html button 隐藏_java servlet与html数据交互初体验
  5. XmlSerializer 对象序列化成XML 自定义编码格式(gb2312)
  6. python做圆柱绕流_圆柱绕流
  7. IOS笔记CALayer的position和anchorPoint
  8. vs在release下调试时局部变量值错位修复
  9. 在Struts 2中使用JSON Ajax
  10. 爱奇艺发布新款电视果,AI 语音控制,4G、WiFi 双模式投屏!
  11. python 实例化过程_python实例化对象的具体方法
  12. 爬虫python需要安装吗_python爬虫需要安装什么
  13. html百分比实现边框而不挤出
  14. UE4.26官方文档网页浏览录屏打包下载版
  15. python语音识别终极指南_Python语音识别终极指南-帮你完成那个最难的从0到1
  16. Ubuntu下自制douban.fm播放器
  17. Python运维(六)--系统监控psutil、数据报scapy、扫描nmap
  18. CA服务器的搭建和申请证书
  19. ps打造人物光滑的肤色
  20. 自动化测试金字塔与反模式

热门文章

  1. 更可靠的数据仓库平台
  2. ubuntu20.04安装微信,亲测有用
  3. 你的视频是否是这样?优秀的视频作品,每个镜头时长不超过10s
  4. ubuntu 14 LAMP
  5. cad07无法看见教育版的标注
  6. 曲速未来 消息:警惕 Locky Poser,PyLocky Ransomware
  7. 【OBS-studio】 CMakeList阅读2 ( libobs plugin)
  8. Spring Boot:实现MyBatis分页
  9. vivo春招java工程师Android方向实习生面试复盘
  10. 被程序员鄙视的“开发者5个等级”划分