不得不看之ReactNative中的狀態(tài)欄

預(yù)備知識(shí)

成都創(chuàng)新互聯(lián)公司為企業(yè)級(jí)客戶提高一站式互聯(lián)網(wǎng)+設(shè)計(jì)服務(wù),主要包括網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)、成都app軟件開發(fā)、重慶小程序開發(fā)公司、宣傳片制作、LOGO設(shè)計(jì)等,幫助客戶快速提升營(yíng)銷能力和企業(yè)形象,創(chuàng)新互聯(lián)各部門都有經(jīng)驗(yàn)豐富的經(jīng)驗(yàn),可以確保每一個(gè)作品的質(zhì)量和創(chuàng)作周期,同時(shí)每年都有很多新員工加入,為我們帶來大量新的創(chuàng)意。 

在正式開始之前,我先介紹一些我目前了解下來的相關(guān)知識(shí),為后面的內(nèi)容進(jìn)行一些鋪墊。

iOS 中的狀態(tài)欄

在 iOS 中,頁(yè)面默認(rèn)全屏(狀態(tài)欄不占空間),狀態(tài)欄內(nèi)容默認(rèn)是深色。因?yàn)轫?yè)面全屏,所以如果我們不進(jìn)行處理,內(nèi)容會(huì)跑到狀態(tài)欄下面去。同時(shí),由于 iPhone X 等劉海屏手機(jī)的出現(xiàn),導(dǎo)致狀態(tài)欄的高度發(fā)生了變化,由之前的?20?變成了?34。為了解決此問題,我們可以手動(dòng)給頂部組件設(shè)置?paddingTop(值根據(jù)機(jī)型判斷),或者使用?SafeAreaView?組件。

在 iOS 中我們只用處理好安全區(qū)域的問題,然后根據(jù)頁(yè)面的不同去設(shè)置內(nèi)容的顏色深淺即可。

Android 中的狀態(tài)欄

在 Android 中,頁(yè)面默認(rèn)非全屏(狀態(tài)欄占空間),狀態(tài)欄內(nèi)容默認(rèn)是淺色。

Android 中對(duì)狀態(tài)欄的支持經(jīng)歷了幾個(gè)版本:

  • Android4.4(API 19) ~ Android 5.0(API 21):通過?FLAG_TRANSLUCENT_STATUS?設(shè)置頁(yè)面為全屏且狀態(tài)欄半透明(淺灰色)。

  • Android 5.0(API 21):提供了?droid:statusBarColor?屬性和?setStatusBarColor?方法用來設(shè)置狀態(tài)欄的顏色。

  • Android 6.0(API 23):通過?SYSTEM_UI_FLAG_LIGHT_STATUS_BAR?支持設(shè)置狀態(tài)欄內(nèi)容為深色。

其中,如果想要設(shè)置狀態(tài)欄顏色,則不能設(shè)置?FLAG_TRANSLUCENT_STATUS。

在 Android 應(yīng)用中,每個(gè) Activity 都對(duì)應(yīng)一個(gè)狀態(tài)欄。這意味著,為一個(gè)頁(yè)面設(shè)置狀態(tài)欄不會(huì)對(duì)其他頁(yè)面的狀態(tài)欄造成影響。

React Native 中的狀態(tài)欄

React Native 官方提供了?StatusBar?組件用于控制狀態(tài)欄,支持設(shè)置內(nèi)容深淺色,狀態(tài)欄背景(Android)等。

StatusBar?可以同時(shí)添加多個(gè),而屬性則會(huì)按照加載順序合并(后者覆蓋前者)。

不同于 Android 中的狀態(tài)欄,在 React Native 中狀態(tài)欄是公用的,任何一個(gè)地方修改狀態(tài)欄都會(huì)導(dǎo)致狀態(tài)欄發(fā)生變化,即使切換到了其他未設(shè)置的頁(yè)面。因此,我們需要在每個(gè)頁(yè)面渲染時(shí)都設(shè)置一下相應(yīng)的狀態(tài)欄,或是在離開設(shè)置了狀態(tài)欄的頁(yè)面時(shí)重置狀態(tài)欄。

實(shí)際案例

在了解了必要的知識(shí)后,讓我們通過一個(gè)實(shí)際案例來看看我們需要做什么以及怎么做才更好。

在這個(gè)案例中,有三個(gè)頁(yè)面:主頁(yè),我的,登錄。其中“主頁(yè)”和“我的”是兩個(gè)標(biāo)簽頁(yè),“主頁(yè)”頭部有背景圖片,“我的”頁(yè)面頂部是藍(lán)色,“登錄”頁(yè)面頂部為白色。頁(yè)面效果如下圖。

不得不看之React Native 中的狀態(tài)欄

“主頁(yè)”和“我的”頁(yè)面使用自定義的 Header,該組件會(huì)根據(jù)當(dāng)前設(shè)備,獲取狀態(tài)欄的高度:

const?STATUS_BAR_HEIGHT?=?isiOS()???(isiPhoneX()???34?:?20)?:?StatusBar.currentHeight

其中判斷設(shè)備使用的下面的方法:

//?iPhone?X、iPhone?XS
const?X_WIDTH?=?375;
const?X_HEIGHT?=?812;
//?iPhone?XR、iPhone?XS?Max
const?XSMAX_WIDTH?=?414;
const?XSMAX_HEIGHT?=?896;

const?DEVICE_SIZE?=?Dimensions.get('window');
const?{?height:?D_HEIGHT,?width:?D_WIDTH?}?=?DEVICE_SIZE;

export?const?isiOS?=?()?=>?Platform.OS?===?'ios'

export?const?isiPhoneX?=?()?=>?{
??return?(
????isiOS()?&&
????((D_HEIGHT?===?X_HEIGHT?&&?D_WIDTH?===?X_WIDTH)?||
??????(D_HEIGHT?===?X_WIDTH?&&?D_WIDTH?===?X_HEIGHT))?||
????((D_HEIGHT?===?XSMAX_HEIGHT?&&?D_WIDTH?===?XSMAX_WIDTH)?||
??????(D_HEIGHT?===?XSMAX_WIDTH?&&?D_WIDTH?===?XSMAX_HEIGHT))
??);
};

獲取到狀態(tài)欄的高度之后,根據(jù)當(dāng)前是不是全屏(fullSreen?屬性為?true?或者是 iOS 設(shè)備)來設(shè)置自身高度和?paddingTop,標(biāo)題欄高度統(tǒng)一設(shè)置為?44。

const?headerStyle?=?[
??styles.header,
??(fullScreen?||?isiOS())?&&?{
??????height:?STATUS_BAR_HEIGHT?+?HEADER_HEIGHT,
??????paddingTop:?STATUS_BAR_HEIGHT
??}
]

“登錄”頁(yè)面的 Header 則是?react-navigation?默認(rèn)的 Header 組件,在 Android 中標(biāo)題欄高度被設(shè)置為?56

處理狀態(tài)欄的問題

從上圖的案例中,可以發(fā)現(xiàn)以下幾點(diǎn)問題:

  1. iOS 設(shè)備中,狀態(tài)欄內(nèi)容的顏色顯示不正確,“主頁(yè)”和“我的”頁(yè)面狀態(tài)欄應(yīng)該是淺色。

  2. Android 設(shè)備中,“主頁(yè)”的狀態(tài)欄應(yīng)該是透明的,并且圖片應(yīng)該延伸到狀態(tài)欄下。

  3. Android 設(shè)備中,“我的”頁(yè)面狀態(tài)欄顏色應(yīng)該也是藍(lán)色。

為了讓應(yīng)用表現(xiàn)得更好,我們需要根據(jù)頁(yè)面動(dòng)態(tài)的調(diào)整狀態(tài)欄。React Native 為開發(fā)者提供了?StatusBar?組件去控制狀態(tài)欄。

StatusBar 組件控制狀態(tài)欄

我們?cè)凇爸黜?yè)”中,設(shè)置狀態(tài)欄內(nèi)容為“淺色”,背景色為透明,translucent?為?true。然后,“主頁(yè)”和“我的”頁(yè)面的 Header 都添加?fullScreen?屬性。效果如下:

不得不看之React Native 中的狀態(tài)欄

從圖中可以看到,因?yàn)轫?yè)面路由是 js 層做的,整個(gè)應(yīng)用對(duì)應(yīng)一個(gè)?StatusBar,雖然“我的”和“登錄”頁(yè)面都沒有設(shè)置狀態(tài)欄,但狀態(tài)欄也是透明的。

這樣就有一個(gè)問題,“登錄”頁(yè)面其實(shí)使用默認(rèn)效果即可,但是由于其他頁(yè)面設(shè)置了狀態(tài)欄,導(dǎo)致進(jìn)入到“登錄”頁(yè)面時(shí)效果就不對(duì)了。所以,每個(gè)頁(yè)面都需要設(shè)置相應(yīng)的狀態(tài)欄,因?yàn)闋顟B(tài)欄可能被其他頁(yè)面改變。

接下來,在“登錄”頁(yè)面設(shè)置狀態(tài)欄為白色且內(nèi)容為深色:

<StatusBar?translucent={false}?backgroundColor='#fff'?barStyle="dark-content"?/>

不得不看之React Native 中的狀態(tài)欄

現(xiàn)在“登錄”頁(yè)面的效果就和期望的一樣了,當(dāng)我們從“登錄”頁(yè)面返回到主界面時(shí),狀態(tài)欄會(huì)切換回之前的狀態(tài),但是有一點(diǎn)延時(shí)。按照前面的經(jīng)驗(yàn),當(dāng)從登錄頁(yè)面回來時(shí),狀態(tài)欄應(yīng)該仍是白色且內(nèi)容深色。因?yàn)榉祷貢r(shí),前面的頁(yè)面不會(huì)重新渲染,狀態(tài)欄應(yīng)該會(huì)保持當(dāng)前的狀態(tài)。但是狀態(tài)欄卻自動(dòng)調(diào)整成了之前的狀態(tài),雖然有一點(diǎn)延時(shí)。我在?react-navigation?的?GitHub issue?中發(fā)現(xiàn)有人提到,當(dāng)離開?route?時(shí),會(huì)自動(dòng)的重設(shè)狀態(tài)欄。我沒有具體研究,但我認(rèn)同這一點(diǎn),這必然是某處做了此類處理。

那為什么會(huì)有延時(shí)呢?我猜測(cè)這應(yīng)該是自動(dòng)重置狀態(tài)欄的時(shí)機(jī)導(dǎo)致的。我嘗試增加了一個(gè)注冊(cè)頁(yè)面(由登錄頁(yè)面點(diǎn)擊按鈕進(jìn)入),并設(shè)置狀態(tài)欄為紅色。然后,我在登錄頁(yè)面監(jiān)聽了?willFocus?和?didFocus?事件,分別在事件的處理函數(shù)中,將狀態(tài)欄設(shè)置為白色。結(jié)果是,在?willFocus?中處理是我們期望的結(jié)果,而?didFocus?中處理和默認(rèn)不處理時(shí)是一樣的。

不得不看之React Native 中的狀態(tài)欄

到這里,我們基本可以得出一個(gè)結(jié)論:如果我們要在 app 中調(diào)整狀態(tài)欄,穩(wěn)妥的做法是在每一個(gè)頁(yè)面?willFocus?時(shí)設(shè)置其相應(yīng)的狀態(tài)欄,除非能確保前一個(gè)頁(yè)面的狀態(tài)欄和自身相同。

因?yàn)檫@個(gè)功能十分通用,所以我們可以通過一個(gè)高階組件來完成這件事:

import?React?from?'react'
import?hoistNonReactStatics?from?'hoist-non-react-statics'
import?{?StatusBar?}?from?'react-native'

import?{?isAndroid?}?from?'../../utils/device'

export?const?setStatusBar?=?(statusbarProps?=?{})?=>?WrappedComponent?=>?{??
class?Component?extends?React.PureComponent?{
????constructor(props)?{
??????????super(props)
??????????this._navListener?=?props.navigation.addListener('willFocus',?this._setStatusBar)
????}

????componentWillUnmount()?{
??????????this._navListener.remove();
????}

????_setStatusBar?=?()?=>?{??????
????const?{
????????barStyle?=?"dark-content",
????????backgroundColor?=?'#fff',
????????translucent?=?false
??????}?=?statusbarProps
??????StatusBar.setBarStyle(barStyle)
??????if?(isAndroid())?{
????????StatusBar.setTranslucent(translucent)
????????StatusBar.setBackgroundColor(backgroundColor);
??????}
????}

????render()?
????{??????return?<WrappedComponent?{...this.props}?/>
????}
??}

??return?hoistNonReactStatics(Component,?WrappedComponent);
}

通過裝飾器的方式使用也十分簡(jiǎn)單:

@setStatusBar({
??barStyle:?'light-content',
??translucent:?true,??
??backgroundColor:?'transparent'})
??export?default?class?Home?extends?React.PureComponent?{
?...?
}

設(shè)置 Android 全屏且狀態(tài)欄透明

除了在 js 層通過?StatusBar?組件設(shè)置狀態(tài)欄的顏色、半透明等,我們也可以先將 Android 的狀態(tài)欄設(shè)置為全屏且狀態(tài)欄透明,這樣 Android 的表現(xiàn)就和 iOS 一樣,可以統(tǒng)一的去處理。

在?MainActivity.java?中添加下面的代碼,可以設(shè)置全屏且狀態(tài)欄透明:

protected?void?onCreate(Bundle?savedInstanceState)?{????super.onCreate(savedInstanceState);

????View?decorView?=?getWindow().getDecorView();
????decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN?|?View.SYSTEM_UI_FLAG_LAYOUT_STABLE);????if?(Build.VERSION.SDK_INT?>=?21)?{
????????getWindow().setStatusBarColor(Color.TRANSPARENT);
????}
}

設(shè)置完成后的效果如下圖(沒有處理?paddingTop)。

不得不看之React Native 中的狀態(tài)欄

現(xiàn)在 Android 狀態(tài)欄的表現(xiàn)就和 iOS 一樣了,處理的時(shí)候統(tǒng)一按照 iOS 的處理邏輯即可,只是在 Header 的高度以及?paddingTop?的計(jì)算上不同。

此外,還需要注意?react-native?的 Header 沒有處理 Android 全屏的情況,因此我們需要在 Android 平臺(tái)下修改?headerStyle:

defaultNavigationOptions:?{
??headerStyle:?{
????...Platform.OS?===?'android'?&&?{
???????height:?StatusBar.currentHeight?+?44,??????
???????paddingTop:?StatusBar.currentHeight
????}
??}
}

總結(jié)

React Native 中想要讓狀態(tài)欄表現(xiàn)得更好還是需要做一些工作的?,F(xiàn)在看來其實(shí)使用?StatusBar?組件更加的容易一點(diǎn),因?yàn)榧词乖?Android 原生層面設(shè)置了全屏和透明狀態(tài)欄,最后還是需要根據(jù)頁(yè)面去設(shè)置狀態(tài)欄內(nèi)容的顏色,所以還不許統(tǒng)一的在 js 層去做,通過高階組件的方式也不是很麻煩。

覺得文章不錯(cuò)的喜歡的小伙伴可以關(guān)注加轉(zhuǎn)發(fā),歡迎大家前來探討交流,同時(shí),我也非常歡迎大家互相交流技術(shù),共同成長(zhǎng)。

分享題目:不得不看之ReactNative中的狀態(tài)欄
瀏覽地址:http://muchs.cn/article10/gphcgo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)全網(wǎng)營(yíng)銷推廣、網(wǎng)站收錄、網(wǎng)站排名、動(dòng)態(tài)網(wǎng)站、網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化