中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

不得不看之React Native 中的狀態欄

發布時間:2020-07-03 09:15:10 來源:網絡 閱讀:1329 作者:Android解析 欄目:移動開發

預備知識

在正式開始之前,我先介紹一些我目前了解下來的相關知識,為后面的內容進行一些鋪墊。

iOS 中的狀態欄

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

在 iOS 中我們只用處理好安全區域的問題,然后根據頁面的不同去設置內容的顏色深淺即可。

Android 中的狀態欄

在 Android 中,頁面默認非全屏(狀態欄占空間),狀態欄內容默認是淺色

Android 中對狀態欄的支持經歷了幾個版本:

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

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

  • Android 6.0(API 23):通過?SYSTEM_UI_FLAG_LIGHT_STATUS_BAR?支持設置狀態欄內容為深色

其中,如果想要設置狀態欄顏色,則不能設置?FLAG_TRANSLUCENT_STATUS

在 Android 應用中,每個 Activity 都對應一個狀態欄。這意味著,為一個頁面設置狀態欄不會對其他頁面的狀態欄造成影響。

React Native 中的狀態欄

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

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

不同于 Android 中的狀態欄,在 React Native 中狀態欄是公用的,任何一個地方修改狀態欄都會導致狀態欄發生變化,即使切換到了其他未設置的頁面。因此,我們需要在每個頁面渲染時都設置一下相應的狀態欄,或是在離開設置了狀態欄的頁面時重置狀態欄。

實際案例

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

在這個案例中,有三個頁面:主頁,我的,登錄。其中“主頁”和“我的”是兩個標簽頁,“主頁”頭部有背景圖片,“我的”頁面頂部是藍色,“登錄”頁面頂部為白色。頁面效果如下圖。

不得不看之React Native 中的狀態欄

“主頁”和“我的”頁面使用自定義的 Header,該組件會根據當前設備,獲取狀態欄的高度:

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

其中判斷設備使用的下面的方法:

//?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))
??);
};

獲取到狀態欄的高度之后,根據當前是不是全屏(fullSreen?屬性為?true?或者是 iOS 設備)來設置自身高度和?paddingTop,標題欄高度統一設置為?44

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

“登錄”頁面的 Header 則是?react-navigation?默認的 Header 組件,在 Android 中標題欄高度被設置為?56

處理狀態欄的問題

從上圖的案例中,可以發現以下幾點問題:

  1. iOS 設備中,狀態欄內容的顏色顯示不正確,“主頁”和“我的”頁面狀態欄應該是淺色

  2. Android 設備中,“主頁”的狀態欄應該是透明的,并且圖片應該延伸到狀態欄下。

  3. Android 設備中,“我的”頁面狀態欄顏色應該也是藍色。

為了讓應用表現得更好,我們需要根據頁面動態的調整狀態欄。React Native 為開發者提供了?StatusBar?組件去控制狀態欄。

StatusBar 組件控制狀態欄

我們在“主頁”中,設置狀態欄內容為“淺色”,背景色為透明,translucent?為?true。然后,“主頁”和“我的”頁面的 Header 都添加?fullScreen?屬性。效果如下:

不得不看之React Native 中的狀態欄

從圖中可以看到,因為頁面路由是 js 層做的,整個應用對應一個?StatusBar,雖然“我的”和“登錄”頁面都沒有設置狀態欄,但狀態欄也是透明的。

這樣就有一個問題,“登錄”頁面其實使用默認效果即可,但是由于其他頁面設置了狀態欄,導致進入到“登錄”頁面時效果就不對了。所以,每個頁面都需要設置相應的狀態欄,因為狀態欄可能被其他頁面改變。

接下來,在“登錄”頁面設置狀態欄為白色且內容為深色:

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

不得不看之React Native 中的狀態欄

現在“登錄”頁面的效果就和期望的一樣了,當我們從“登錄”頁面返回到主界面時,狀態欄會切換回之前的狀態,但是有一點延時。按照前面的經驗,當從登錄頁面回來時,狀態欄應該仍是白色且內容深色。因為返回時,前面的頁面不會重新渲染,狀態欄應該會保持當前的狀態。但是狀態欄卻自動調整成了之前的狀態,雖然有一點延時。我在?react-navigation?的?GitHub issue?中發現有人提到,當離開?route?時,會自動的重設狀態欄。我沒有具體研究,但我認同這一點,這必然是某處做了此類處理。

那為什么會有延時呢?我猜測這應該是自動重置狀態欄的時機導致的。我嘗試增加了一個注冊頁面(由登錄頁面點擊按鈕進入),并設置狀態欄為紅色。然后,我在登錄頁面監聽了?willFocus?和?didFocus?事件,分別在事件的處理函數中,將狀態欄設置為白色。結果是,在?willFocus?中處理是我們期望的結果,而?didFocus?中處理和默認不處理時是一樣的。

不得不看之React Native 中的狀態欄

到這里,我們基本可以得出一個結論:如果我們要在 app 中調整狀態欄,穩妥的做法是在每一個頁面?willFocus?時設置其相應的狀態欄,除非能確保前一個頁面的狀態欄和自身相同。

因為這個功能十分通用,所以我們可以通過一個高階組件來完成這件事:

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);
}

通過裝飾器的方式使用也十分簡單:

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

設置 Android 全屏且狀態欄透明

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

在?MainActivity.java?中添加下面的代碼,可以設置全屏且狀態欄透明:

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);
????}
}

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

不得不看之React Native 中的狀態欄

現在 Android 狀態欄的表現就和 iOS 一樣了,處理的時候統一按照 iOS 的處理邏輯即可,只是在 Header 的高度以及?paddingTop?的計算上不同。

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

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

總結

React Native 中想要讓狀態欄表現得更好還是需要做一些工作的。現在看來其實使用?StatusBar?組件更加的容易一點,因為即使在 Android 原生層面設置了全屏和透明狀態欄,最后還是需要根據頁面去設置狀態欄內容的顏色,所以還不許統一的在 js 層去做,通過高階組件的方式也不是很麻煩。


覺得文章不錯的喜歡的小伙伴可以關注加轉發,歡迎大家前來探討交流,同時,我也非常歡迎大家互相交流技術,共同成長。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武强县| 邯郸市| 宁德市| 桑植县| 贵溪市| 金川县| 辽源市| 辉县市| 青海省| 湖州市| 花垣县| 类乌齐县| 安平县| 辽宁省| 大同市| 龙游县| 万全县| 津南区| 湄潭县| 谷城县| 石楼县| 卢龙县| 成都市| 长汀县| 海原县| 新蔡县| 垣曲县| 梓潼县| 和平区| 九龙县| 廊坊市| 上蔡县| 潮州市| 隆德县| 宁夏| 贺兰县| 抚顺市| 抚州市| 大关县| 宜君县| 阿克陶县|