1. 三方庫(調(diào)用原生)的使用
這里的三方庫特指需要調(diào)用原生的庫,目前項目里用到了react-native-share(分享)、react-native-linear-gradient(漸變)、react-native-splash-screen(閃屏)、react-native-svg(svg)。
正常我們使用react-native link命令,原生依賴就成功地鏈接到你的iOS/Android項目了,但出于原生代碼可能被改寫的情況,需要在原生代碼中確認一下引入情況:

2. lineHeight
在遷移過程發(fā)現(xiàn)幾個頁面都出現(xiàn)一下錯誤提示:
Error while updating property 'lineHeight' in shadow node of type:RCTText
查文檔給出的解釋:
lineHeight must be an integer, numbers with decimals are not considered as valid values.
原來安卓上lineHeight必須是整數(shù),由于我們的項目中用了p2dp進行適配,會有把整數(shù)轉(zhuǎn)成了小數(shù)的情況,解決方法就是p2dp的結(jié)果進行向上取整。
3. 字體引入
安卓上要使用自定義的字體,必須要把字體文件放在[project root]/android/app/src/main/assets/fonts/目錄下才能生效。
4. StatusBar
StatusBar是一個值得被重視的差異,它會影響到頭部導(dǎo)航的高度樣式問題,甚至是整個頁面的高度問題。
4.1 StatusBar高度
- 4.1.1 Android 手機狀態(tài)欄
(1)當狀態(tài)欄呈現(xiàn)在 Andorid 手機屏幕頂部時,它會占用頂部這個空間,我們只能使用剩下的屏幕空間。也就是說如果從第 0 行開始放置組件時,組件會緊貼著狀態(tài)欄的下邊沿顯示;
(2)要想知道實際可用的屏幕高度,可以通過手機屏幕的高度減去狀態(tài)欄高度得到,安卓狀態(tài)欄的高度可通過StatusBar.currentHeight獲取。 - 4.1.2 iOS 手機狀態(tài)欄
(1)在 iOS 平臺上,取得的屏幕高度就是實際可使用的高度;
(2)如果從第 0 行開始排列組件時,組件會緊貼著手機屏幕的最上沿顯示。如果狀態(tài)欄沒有被隱藏,它將覆蓋在第 0 行組件的上方;
(3)如果不想設(shè)置狀態(tài)欄隱藏,則應(yīng)當空出狀態(tài)欄的顯示區(qū)域。但可以為這個區(qū)域設(shè)置背景色,以使整個界面風(fēng)格統(tǒng)一。
4.2 StatusBar樣式
Default status bar style (dark for iOS, light for Android)
在Android上默認的樣式是白色,而IOS是黑色,所以當我們在跨平臺設(shè)置StatusBar樣式時,避免使用defult,應(yīng)該直接使用light-content、dark-content
4.3 StatusBar背景色
Android上可通過backgroundColor設(shè)置背景色,而IOS無此屬性,需要通過手動設(shè)置20dp高度的顏色作為背景色。另外項目中有個特殊需求,需要StatusBar的顏色是漸變的,這時安卓上需要讓背景色透明,設(shè)置同等高度的漸變色來替代。
5. 閃屏、廣告頁面
因為閃屏涉及端代碼的編寫,自然需要重新開發(fā)。
廣告頁面則有兩個思路:可以在端開發(fā)、也可以放在RN:
- 在端的好處在于RN的首頁是"真首頁",在啟動應(yīng)用顯示閃屏的時候,為預(yù)加載首頁提供了時間,讓首頁出現(xiàn)的時間大大提升;缺點就是不夠靈活,如果將廣告圖換一個表現(xiàn)形式,需要重新發(fā)包。
- 在RN的好處自然就是靈活,可以頻繁的變換廣告形式也無需更新App,另外如果是復(fù)雜的廣告形式,對于前端開發(fā)人員,開發(fā)端代碼的陳本要遠高于開發(fā)RN;缺點就是RN的首頁變成了廣告頁,而不是我們想要的首頁,這樣啟動圖無法爭取到首頁的訪問的時間,在首頁呈現(xiàn)的時間上肯定比上面的方法慢一些。
6. 輪播組件
這個問題涉及到了第三方組件的兼容性。
之前在IOS上用的Carousel組件在Android會有一些異常的表現(xiàn)。解決方案有兩種:
- 修改組件源碼,修復(fù)異常;
- 用一個兼容性沒問題的同類組件替換
在解決過程中兩種辦法都嘗試過,都可行。從這里也獲取一個經(jīng)驗,之后在選擇三方庫的時候,盡量選擇更新時間近、star數(shù)量高、仍在維護、大廠出品的。
7. 監(jiān)聽物理回退
由于安卓機子有一個物理回退鍵,如果在RN項目中不對其處理,則點擊物理回退鍵就會關(guān)閉App,而我們的預(yù)期是希望點擊后回退上一頁。
首頁我們要知道,點擊物理回退,其實會調(diào)用端的onBackPressed方法,所以我們需要判斷如果是RN頁面,應(yīng)該讓RN代碼自行決定處理方式,當然這層邏輯其實初始化項目就做好了:
@Override
public void onBackPressed() {
//super.onBackPressed();
if(mReactInstanceManager != null){
mReactInstanceManager.onBackPressed();
}else{
super.onBackPressed();
}
}
這樣我們只需要在RN項目里監(jiān)聽這個回退,然后處理自己想要的邏輯就行了,代碼大致如下:
componentDidMount() {
if (Platform.OS === 'android') {
BackHandler.addEventListener('hardwareBackPress', this._handleBack.bind(this));
}
}
componentWillUnmount() {
if (Platform.OS === 'android') {
BackHandler.removeEventListener('hardwareBackPress', this._handleBack.bind(this));
}
}
只需要在程序入口做一次監(jiān)聽,后續(xù)頁面無需處理。
8. Modal
Android平臺Modal組件中的onRequestClose是一個必傳參數(shù),IOS則不需要。
可以在Modal的文檔上可以看到關(guān)于onRequestClose參數(shù)的描述:
On the Android platform, this is a required function.
至于為什么只有安卓平臺需要,我猜大概率和物理回退的相關(guān)處理有關(guān)系。
9. 自定義字體的高度問題
目前項目中引入了兩個外部字體:思源宋和閱文定制的數(shù)字字體。
引入字體會有一定高度的上下pandding,樣式處理上也有別于常規(guī)字體,需要設(shè)置lineHeight、height更好的定位位置。
10. Text樣式之ellipsizeMode屬性
Text樣式中的ellipsizeMode屬性 , 用來配合numberOfLines 顯示不完全省略的位置, 可選值'head', 'middle','tail','clip',而其中'clip'只能在IOS中使用,安卓平臺會報錯。
11. popover組件
這個問題同問題6,一樣涉及到了第三方組件的兼容性。
其中比較核心的問題是安卓平臺上不支持shadow陰影屬性的設(shè)置,這個問題在下一條會提到。
另外這個庫的開發(fā)時間比較早且已經(jīng)無人維護,所以類似這樣的庫以后應(yīng)該規(guī)避。
至于最終的解決方案,其實是加了一層蒙層來替代陰影的效果。
12. 陰影屬性
在IOS上可以通過如下設(shè)置陰影:
shadowOffset: {width: 0, height: 0},
shadowColor: 'black',
shadowOpacity: 1,
shadowRadius: 5
而Android上并不支持shadow相關(guān)的屬性,只提供了一個elevation屬性,使用方法如下:
backgroundColor: 'black',
elevation: 20,
elevation顧名思義就是 “仰角”,通過為視圖增加 “仰角” 方式來提供陰影,仰角越大,陰影越大。
但elevation的設(shè)置比較局限,設(shè)置無法設(shè)置offset。如果需要更好的效果,還是需要通過其它方式去實現(xiàn),svg、漸變等,當然也有這樣庫提供了解決方案,像react-native-shadow、react-native-cardview都是值得參考的。
13. 觸摸點擊
目前關(guān)于觸摸點擊有以下幾種方式:
- TouchableHighlight
? What it does: Darkens or lightens the background of the element when pressed.
? When to use it: On iOS for touchable elements or buttons that have a solid shape or background, and on ListView items.
- TouchableOpacity
? What it does: Lightens the opacity of the entire element when pressed.
? When to use it: On iOS for touchable elements that are standalone text or icons with no backgroundcolor.
- TouchableNativeFeedback
? What it does: Adds a ripple effect to the background when pressed.
? When to use it: On Android for almost all touchable elements.
安卓平臺推薦用TouchableNativeFeedback
14. TextInput
TextInput在安卓平臺默認有下劃線且框內(nèi)文字樣式也有問題,需要做如下兼容處理:
underlineColorAndroid = "transparent" //android需要設(shè)置下劃線為透明才能去掉下劃線
style={{padding:0}}// 矯正樣式
15. ScrollView
我們觀察Android和IOS默認的下拉刷新表現(xiàn)形式是不一樣的,這是因為安卓上的ScrollView沒有IOS的彈性bounces,這也使得我們通過onScroll、onScrollEndDrag獲取X軸、Y軸距離做的一些判斷會有所區(qū)別。
16. react-native-scrollable-tab-view組件卡頓
這個組件在切換兩個數(shù)據(jù)量稍大的Tab時,就會有明顯的卡頓,開始以為是性能問題導(dǎo)致動畫卡頓,后來debug發(fā)現(xiàn)是組件在切換回已經(jīng)render的view,還做了一次render,導(dǎo)致阻塞了動畫的執(zhí)行,解決辦法是通過shouldComponentUpdate判斷是否有必要render,當然也可以使用PureComponent來實現(xiàn)。