react-native 在android封装原生listView
2017-04-11 10:08
537 查看
react-native 在android封装原生listView
前言
react-native中的ListView的性能问题是react-native开发的一个痛点。虽然0.43中推出了FlatList,但是快速滑动的时候的白屏问题仍然是很影响用户体验。最近在项目中需要使用react-native开发相册,在经过再三的考虑后,决定直接封装原生的listView。虽然这样做使得ios、android的代码不可共用,也放弃了react-native热更新的优势,但却实实在在的拥有了原生的性能。
问题
ios轻易的完成了封装,但是android这边却遇到了坑–listView的更新实时,setAdapter或者adapter.notifyDataSetChanged后页面没有进行相应的更新,必须滚动页面后才会进行相应的刷新。思考
作为一名程序猿,首先当然是上google去了。遗憾的是没有找到任何有用的信息,甚至没有人提出这个问题。没办法,自己撸源码去。首先看了一下listView中setAdapter和adapter.notifyDataSetChanged的源码,发现其最终都是调用requestLayout来更新页面的。然后,我就去查了一下requestLayout到底做了什么:
在requestLayout方法中,首先先判断当前View树是否正在布局流程,接着为当前子View设置标记位,该标记位的作用就是标记了当前的View是需要进行重新布局的,接着调用mParent.requestLayout方法,这个十分重要,因为这里是向父容器请求布局,即调用父容器的requestLayout方法,为父容器添加PFLAG_FORCE_LAYOUT标记位,而父容器又会调用它的父容器的requestLayout方法,即requestLayout事件层层向上传递,直到DecorView,即根View,而根View又会传递给ViewRootImpl,也即是说子View的requestLayout事件,最终会被ViewRootImpl接收并得到处理。纵观这个向上传递的流程,其实是采用了责任链模式,即不断向上传递该事件,直到找到能处理该事件的上级,在这里,只有ViewRootImpl能够处理requestLayout事件。– Android View 深度分析requestLayout、invalidate与postInvalidate
解决
既然requestLayout是层层向上传递,那么问题就应该是在父view上了。作为一个控件,在使用中,其父view必然是一个react-native的控件。而react-native的view大部分是继承View,所以我又查看了一下VIew的原生实现ReactVIewGroup的源码,终于找到了原因所在:@Override public void requestLayout() { // No-op, terminate `requestLayout` here, UIManagerModule handles laying out children and // `layout` is called on all RN-managed views by `NativeViewHierarchyManager` }
React-Native重写了ReactViewGroup的requestLayout方法,这使得ListView在使用requestLayout的时候无法事件无法传递到ViewRootImpl。就是说,所有的view在ReactNative都将失效。
知道问题所在,事情就好解决了。在Stack Overflow找到了解决的方法:
@Override public void requestLayout() { super.requestLayout(); // The spinner relies on a measure + layout pass happening after it calls requestLayout(). // Without this, the widget never actually changes the selection and doesn't call the // appropriate listeners. Since we override onLayout in our ViewGroups, a layout pass never // happens after a call to requestLayout, so we simulate one here. post(measureAndLayout); } private final Runnable measureAndLayout = new Runnable() { @Override public void run() { measure( MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); layout(getLeft(), getTop(), getRight(), getBottom()); } };
http://stackoverflow.com/questions/39836356/react-native-resize-custom-ui-component
相关文章推荐
- React Native之原生UI组件封装---适配Android
- [置顶] React-Native开发之原生模块封装(Android)升级版
- React Native之原生UI组件封装---适配Android
- React Native封装Android原生控件
- React-Native开发之原生模块封装(Android)升级版
- react native学习笔记25——Android原生模块的封装与调用
- React Native植入原生Android应用的流程解析
- 【React Native开发】React Native移植原生Android项目(4)
- Android原生应用集成ReactNative坑总结
- react native 学习笔记----将react native嵌入到Android原生应用
- 原生Android项目中集成React native页面
- Android原生嵌入React Native详解
- React Native移植原生Android
- Android 原生开发、H5、React-Native使用利弊和场景技术分享
- React Native调用Android原生模块
- React Native添加Android原生模块
- Android React Native使用原生模块
- React native 移植原生android module
- 【react-native-0.31-iOS】封装原生组件并调用(02)
- 关于React-native里Android原生模块和组件的写法