1.onResponderMove有时候返回值不对的问题
在做进度条的时候,处理onResponderMove的事件的时候,有时候发现进度条在拖动的时候跳动,最后发现原因是onResponderMove返回的event值有些问题。
这是布局
<View style={[styles.container , this.props.style]}
pointerEvents = "box-only"
onStartShouldSetResponder = {()=>{return true}}
onMoveShouldSetResponder = {()=>{return true}}
onResponderStart = {this._onResponderStart.bind(this)}
onResponderMove = {this._onResponderMove.bind(this)}
onResponderRelease = {this._onResponderRelease.bind(this)}
onLayout = {this._onLayout.bind(this)}>
<View style = {[ styles.progressBackground, { height:progressHeight }]}/>
<View style = {[styles.secondProgress, { marginTop : -progressHeight, height:progressHeight , width:this.state.secondProgress}]}/>
<View style = {[ styles.firstProgress, { marginTop : -progressHeight,height:progressHeight , width:firstProgressWidth}]}/>
<View style = {[styles.slider , {position:"absolute" , left:firstProgressWidth}]}/>
最后发现是因为view堆叠在一块,触摸的时候事件返回的位置信息有点问题。最好处理就是事件只让最外面View处理就行路。
最后查看资料有一个叫pointerEvent的属性,是用来处理堆叠在一起的View事件的属性。看路文档之后最后选择“box-only”完美解决
pointerEvent官方介绍
pointerEvent参考
2.onResponderMove的参数event.nativeEvent.locationX不会更新的问题
这是React Native的一个bug,正在Android中出现,IOS没有问题
参见issue
在最新的版本中已经修复了,但是在低版本中有问题
还好event.nativeEvent.pageX这个值更新了,就用这个值来解决问题就行了
解决办法如下:
var x = event.nativeEvent.locationX;
if (Platform.OS === "android"){
x = event.nativeEvent.pageX - this.layout.x
}
在0.44.3中是有问题的,最新版本修复此bug
3.Component的生命周期控制
我本人是做原生开发的,遇到这个问题是做视频全屏切换需求的时候,要是原生开发其实就很简单了,直接将VideoView放到Activity的根View当中就可以了,这样切换的时候,VideoView不会被销毁在重新创建。天真的我在ReactNative当中也想这也搞,最后发现你根本控制不了Component的生命周期。
假设VideoComponent对应的原生的VideoViewMananger。那么在VideoComponent挂载的时候会调用VideoViewManager的createNewInstance来创建新的实例。在卸载的时候也会调用onDropViewInstance。
所以在RN当中,View组件的节点与节点之间的层级一般是不能改变的。并不能简单的像在原生开发当中,将一个View移除,在添加到另一个ViewGroup当中。
4.React Native 没有遵守Android的View的测量,布局,绘制,这个流程
在RN自定义View组件的时候,在自定义的View组件中掉用requestLayout不会引发重新布局的。
原因:在ReactRootView当中的onLayout没事实现
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// No-op since UIManagerModule handles actually laying out children.
}
所以布局到ReactRootView就停止了,不会继续传递下去。
这会有什么问题呢?会让你在自定义一些复杂组件的时候,内部的View如果需要重新布局,可能就很麻烦。
假如,我们要做一个VideoView的组件,VideoView可能是一个RelativeLayout,里面放一个SurfaceView。一般在mediaPlayer回调视频宽高的方法的时候需要对SurfaceView重新计算大小和布局,这是就要发送一个requestLayout请求。
在RN下一般没反应的,肯定不会重新布局。而RN的源码中给了一个临时方案
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());
}
};
@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);
}
这段代码是在ReactPicker这个类当中复制过来的。
5. React Native 的View 的设计
6.在View组件中onDraw函数
在自定义组件中调用invalidate()会引发视图重绘,RN的绘制也有很大问题。
7. Modal这个类在Android上最好不要用
Modal根本没有考虑上面有对话框的问题,如果Modal覆盖有对话框,从后台切换到前台,Modal会覆盖对话框。
而且Modal的在前后胎切换的时候体验很不好,会重复创建。
8.react native send command to a non-existing view
在JS对接Android原生View的时候出现的。
JS:
<View>
<TALVideoView
dataSource = {this.props.dataSource}
onPreparedEvent = {()=>this.start()}
{ ... this.props}
/>
</View>
Java:
@Nullable
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
Map<String, Object> map = new HashMap<>();
map.put("WL_onPreparedEvent" , MapBuilder.of("registrationName", "onPreparedEvent"));
return map;
}
由于事件不会冒泡传,所以只看最外层的View没有onPreparedEvent就报错了。
方案:去掉最外的View或者用getExportedCustomBubblingEventTypeConstants
9. RN和Kotlin写的模块对接的时候编译的bug
用Kotlin写的模块,对接RN的时候,模块的名字正确没有重复,但是在JS端总是获取不到对象。
const module = NativeModules.xxxxx; //总是返回null
可能是Kotlin编译的问题,clean一下项目在运行就可以了