預(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 中,頁(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 中,頁(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 官方提供了?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í)后,讓我們通過一個(gè)實(shí)際案例來看看我們需要做什么以及怎么做才更好。
在這個(gè)案例中,有三個(gè)頁(yè)面:主頁(yè),我的,登錄。其中“主頁(yè)”和“我的”是兩個(gè)標(biāo)簽頁(yè),“主頁(yè)”頭部有背景圖片,“我的”頁(yè)面頂部是藍(lán)色,“登錄”頁(yè)面頂部為白色。頁(yè)面效果如下圖。
“主頁(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
。
從上圖的案例中,可以發(fā)現(xiàn)以下幾點(diǎn)問題:
iOS 設(shè)備中,狀態(tài)欄內(nèi)容的顏色顯示不正確,“主頁(yè)”和“我的”頁(yè)面狀態(tài)欄應(yīng)該是淺色。
Android 設(shè)備中,“主頁(yè)”的狀態(tài)欄應(yīng)該是透明的,并且圖片應(yīng)該延伸到狀態(tài)欄下。
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)欄。
我們?cè)凇爸黜?yè)”中,設(shè)置狀態(tài)欄內(nèi)容為“淺色”,背景色為透明,translucent
?為?true
。然后,“主頁(yè)”和“我的”頁(yè)面的 Header 都添加?fullScreen
?屬性。效果如下:
從圖中可以看到,因?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"?/>
現(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í)是一樣的。
到這里,我們基本可以得出一個(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?{ ?...? }
除了在 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
)。
現(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 ????} ??} }
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)