#React Native 双平台差异及解决方法(0.20)
--
1. TextInput
- iOS下的
textAlign
取值auto
left
right
center
justify
- android下的
textAlign
取值为start
center
end
安卓平台有黑色边框和选中黄框,可通过设置underlineColorAndroid='rgba(0,0,0,0)'
去掉
安卓平台无清除按钮,可以使用 react-native-textinput 来兼容双平台
2. Image
- iOS下
resizeMode
可以写在行间属性,也可以写在style,后者覆盖前者 - android下
resizeMode
只可以写在行间,写在style无效
//android
<Image resizeMode={'stretch'}></Image>
//ios, style中的cover会覆盖掉stretch
<Image resizeMode={'stretch'} style={{'resizeMode': 'cover'}}></Image>
3. Text
- iOS下最主要的
padding
、lineHeight
的 style 属性都正常支持 - android下
padding
、lineHeight
无效,包括单独支持 android 的textAlignVertical enum('auto', 'top', 'bottom', 'center')
也不支持,解决办法就是padding
改用margin
,或padding
改用父节点padding
;lineHeight
改用marginTop
负值
//双平台
let isAndroid = Platform.OS === 'android';
let styleTextLine1 = {
fontSize: 12,
marginBottom: 20,
};
let styleTextLine2 = {
fontSize: 50,
height: 50,
lineHeight: 50, // ios
marginTop: isAndroid ? -15 : 0,
};
<View style={{height: 100, justifyContent: 'center', alignItems: 'center'}}>
<Text style={styleTextLine1}>第一行,要求与第二行有间隔 20,字体大小 12</Text>
<Text style={styleTextLine2}>第二行,要求字体大小 50,字体上下居中,高度 50</Text>
</View>
4. style position: 'absolute'
- iOS下正常
- android下,
position: 'absolute'
超过父节点高宽部分,会隐藏掉。解决办法:当需要用position: 'absolute'
的时候,恰巧要求:子节点定位超出父节点高或宽,放弃使用,改用别的布局,或者将子节点放到于父节点同级,再定位。
5. style borderRadius
- iOS下正常
- Android下,不支持类似
borderTopLeftRadius
这种写法
--
1. api
NativeMethodsMixin static measure(callback: MeasureOnSuccessCallback)
- iOS下正常
- android下,回调函数获取不到视图的尺寸
x
、y
、width
、heigth
、pageX
、pageY
等值。可以考虑用onLayout
属性来代替,需要注意的是,需要计算 layout 的视图,载入之后,防止内部不必要的重绘引起的尺寸变化,基本上保证 state 改变后,视图的尺寸即可预见。
--
1. 返回事件的处理
- iOS如果使用
NavigatorIOS
,并且设置了navigationBarHidden={true}
(隐藏NavigationBar),将会导致右滑返回手势失效,解决方法:使用Navigator
代替,但需要自己设置切场动画。 - android物理返回键,需要在每个
Navigator
的源头使用BackAndroid
做监听,如果this.navigator.state.routeStack.length === 1
,则可以认为当前处于根view,可以退出app。否则将navigator往回退1即可。
//android
import React, {Navigator, BackAndroid} from 'react-native';
//拓展类似于NavigatorIOS的popN
Navigator.prototype.popN = function(n) {
let routeStack = this.state.routeStack;
let index = routeStack.length - n - 1;
if (routeStack[index]) {
this.popToRoute(routeStack[index]);
}
};
class MyApp extends React.Component {
...
componentDidMount(){
BackAndroid.addEventListener('hardwareBackPress', () => {
//不在根view, 往回退1,阻止退出
if(this._navigator.state.routeStack.length > 1){
this._navigator.popN(1);
return true;
}
//在根view,退出(或再次点击退出)
else{
return false;
}
});
}
render(){
<Navigator
ref={(navigator) => {
if(navigator !== this._navigator){
this._navigator = navigator;
}
}}
/>
}
}
2. 有关屏幕的高度Dimensions.get('window').height
-
两个平台都是整个屏幕的高度(包含statusBar, 安卓端不包含虚拟按键)
-
iOS平台的布局是从statusBar的顶端开始
-
android平台的布局是从statusBar的底端开始(设置
translucent: true
后也从statusBar顶端开始) -
如果设置view的高度是
Dimensions.get('window').height
,然后设置position: 'absolute', top: 0
,会发现android平台view的底端被遮住了一小部分,这一小部分正好就是android平台statusBar的高度 -
安卓端statusBar通常是25dp,虚拟按键通常是48dp
-
解决方法有四:
- 设置view的高度是整屏的高度减去statusBar的高度
- 设置
top
值为负的statusBar的高度 - 设置
bottom: -Dimensions.get('window').height
替代top: 0
- 在每一个
Navigator
的入口设置<StatusBar translucent={true}/>
-
大坑: 有些手机通过上述方法获取到的屏幕高度竟然包含了虚拟按键的高度,如魅族pro4,只能引入react-native-device-info这个库来hack一下了
3. Android过门动画卡顿
- 从测试结果来看是网络请求和过门动作同时进行导致,将网络请求延迟到过门动画结束后即可解决。深层原因?
4. Android启动图launcher
- 修改MainActivity的父类ReactActivity,在加载RN的view的同时在该view上面覆盖一个原生的view,用来显示启动图,并且设置N秒后隐藏或等待拿到首页数据接口后隐藏
5. 支持程度问题
- iOS支持7.0及以上
- Android支持API 16+ (Android 4.1) 因为使用了Choreographer
- 友盟2016-02数据:
- iOS7.0 以下已不计入主流版本(1%以下),和其他非主流版本共占4.92%
- Android4.0 还有2.16%,其他非主流版本共占7.47%