何謂沉浸式狀態(tài)欄##
說白了,沉浸式狀態(tài)欄本質(zhì)上就是給系統(tǒng)狀態(tài)欄著色。當(dāng)這個(gè)顏色和我們Activity
中的ToolBar
或者ActionBar
所使用的背景顏色一致時(shí)就會(huì)有沉浸式的效果。
怎么給狀態(tài)欄著色##
那么我們要怎么樣才能給系統(tǒng)狀態(tài)欄著色呢?谷歌后知后覺,終于在API 21
的Window
類中添加了相應(yīng)的方法,方法聲明如下:
public abstract class Window {
/**
For this to take effect,the window must be drawing the system bar backgrounds with
android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and
android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS must not be set
**/
public abstract void setStatusColor(int color);
}
具體的實(shí)現(xiàn)在PhoneWindow
類中,這里不再深入。既然方法都有了,那么直接調(diào)用就行了。這里我們?cè)?code>Activity中將狀態(tài)欄顏色設(shè)置為紅色:
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#FF0000"));
注意,上面的代碼假設(shè)當(dāng)前系統(tǒng)API Level >= 21
,因?yàn)橹挥袧M足條件的SDK版本才能找到該方法;與此同時(shí),在設(shè)置狀態(tài)欄顏色的同時(shí),API文檔 告訴我們還需要同步設(shè)置WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
這個(gè)Window Flag
,并且需要保證WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
這個(gè)Window Flag
沒有被設(shè)置。否則,不會(huì)生效。
在調(diào)用任何一個(gè)不熟悉的方法時(shí),請(qǐng)首先仔細(xì)閱讀一下API 文檔
上面,我們通過方法調(diào)用給系統(tǒng)狀態(tài)欄著色;當(dāng)然也可以通過指定Theme
來完成;
<style name="MaterialAppTheme" parent="android:Theme.Material.Light">
<item name="android:colorPrimaryDark">#FF0000</item>
<item name="android:statusBarColor">#00FF00</item>
</style>
從Material Theme
中繼承,覆寫android:statusBarColor
屬性,指定具體顏色值即可。Material Theme
中android:statusBarColor
屬性的值默認(rèn)使用android:colorPrimaryDark
屬性指定的值;所以我們也可以僅僅指定android:colorPrimaryDark
屬性;
如果因?yàn)槟撤N原因,不從Material Theme
中繼承,那么就只能老老實(shí)實(shí)地指定特定的屬性不能偷懶,這些屬性包括android:statusBarColor
,android:windowDrawsSystemBarBackgrounds
。
<style name="CustomAppTheme" parent="android:Theme.Light">
<item name="android:statusBarColor">#00FF00</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
這里,我們只從Theme.Light
中繼承,那就不要指望它能像Material Theme
那樣幫我們做一些事;android:statusBarColor
必須指定,因?yàn)樗辉儆心J(rèn)的指向android:colorPrimaryDark
;此外,android:windowDrawsSystemBarBackgrounds
為true
必不可少;就像上面使用setStatusColor
方法時(shí)需要注意的那樣,這個(gè)屬性相當(dāng)于添加了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
(當(dāng)然你也可以不在Theme
中指定這個(gè)屬性,使用如上代碼那種方式添加Window Flag
);而從Material Theme
中繼承時(shí)沒有那樣做,是因?yàn)?code>Material Theme中它默認(rèn)值為true
。
注意,上面Theme
的聲明,對(duì)應(yīng)的資源文件應(yīng)該在values-v21
文件夾下。因?yàn)椴还苁窍鄳?yīng)的屬性,還是對(duì)應(yīng)的Material Theme
都是至少API 21
才能使用的。
兼容低版本
OK,到此為止,我們所討論的都是基于API 21
以上的。如果低版本該怎么辦?低版本的系統(tǒng)是不支持給狀態(tài)欄著色的,但卻可以通過 透明狀態(tài)欄+透明背景顏色 來實(shí)現(xiàn)相同的效果;廢話不多說,來看實(shí)現(xiàn)。
將系統(tǒng)狀態(tài)欄設(shè)置為透明
這是第一步。可以通過代碼方式
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
或者Theme Attribute
的方式
<item name="android:windowTranslucentStatus">true</item>
設(shè)置對(duì)應(yīng)背景顏色
接下來,就是背景顏色的設(shè)置。首先需要將ActionBar
或者ToolBar
的背景顏色設(shè)置為我們需要的顏色,具體如何設(shè)置不再深入,請(qǐng)自行研究(這里,如果沒有使用到ActionBar
或者ToolBar
,這一步可直接略過)。
其次,設(shè)置Activity
根布局的背景顏色為一致的顏色;Just a piece of cake!
最后,我們還需要做一個(gè)調(diào)整。當(dāng)設(shè)置了狀態(tài)欄為透明后,Activity
會(huì)相當(dāng)于一個(gè)FullScreen
的全屏設(shè)置,窗口會(huì)占滿整個(gè)屏幕,整體的內(nèi)容會(huì)往上移動(dòng)一段狀態(tài)欄高度的距離,這樣就會(huì)導(dǎo)致狀態(tài)欄覆蓋到我們的內(nèi)容。這時(shí),我們需要在根布局上設(shè)置android:fitsSystemWindows="true"
,這樣系統(tǒng)會(huì)幫我們重新調(diào)整窗口的位置避免出現(xiàn)覆蓋的情況(無非就是給我們的窗口加上一個(gè)padding值);
注意,上面透明欄+背景色
的方式只適用于API 19
以上,因?yàn)檫@個(gè)版本以上的系統(tǒng)才支持透明化狀態(tài)欄,所以,19
以下的系統(tǒng)不支持沉浸式狀態(tài)欄
其實(shí)系統(tǒng)的導(dǎo)航欄在
API 19
以上同狀態(tài)欄一樣也支持透明化和設(shè)置背景顏色,但這不是本文內(nèi)容
關(guān)于透明化狀態(tài)欄
上面說到android:windowTranslucentStatus
可用于API 19以上的版本透明化狀態(tài)欄;但請(qǐng)注意,在19版本和19版本以上該屬性生效時(shí)存在差異。具體表現(xiàn)如下(這里盜用stackoverflow
上的一張圖說明)
上圖中,左邊為19版本的顯示效果,右邊為21版本的效果;我們可以從圖中看到比較明顯的差異。在19版本中,系統(tǒng)給SystemBar
添加了一個(gè)漸變,而21版本的則是一個(gè)透明的純色。如果我們使用android:windowTranslucentStatus
在21版本及以上來實(shí)現(xiàn)沉浸式的應(yīng)用,則最終效果將不會(huì)太理想;那么是不是就不能實(shí)現(xiàn)了呢?No!
21版本以上的透明系統(tǒng)欄需要使用android:statusBarColor = "@android:color/transparent"
來實(shí)現(xiàn);這里android:windowTranslucentStatus
肯定是為false
的,因?yàn)檫@兩個(gè)屬性是不能同時(shí)生效的。但是由于android:windowTranslucentStatus
屬性的禁用,狀態(tài)欄將不再會(huì)是浮在我們的window
上。沒關(guān)系,我們可以通過下面的方法達(dá)到一樣的效果:
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
其實(shí)設(shè)置android:windowTranslucentStatus
屬性時(shí),正是系統(tǒng)幫我們?cè)O(shè)置了上面的Flag
;上面我們?cè)?code>DecorView上調(diào)用這個(gè)方法,但其實(shí)可以在任何一個(gè)可見的View
上進(jìn)行調(diào)用,效果是一樣的。下面再補(bǔ)充說明一下setSystemUiVisibility
其他可用的標(biāo)志:
View.SYSTEM_UI_FLAG_VISIBLE Level 14 默認(rèn)標(biāo)記
View.SYSTEM_UI_FLAG_LOW_PROFILE Level 14
低功耗模式, 會(huì)隱藏狀態(tài)欄圖標(biāo), 在4.0上可以實(shí)現(xiàn)全屏。status bar和navigation bar的相關(guān)圖標(biāo)會(huì)被弱化,比如navigation bar的幾個(gè)虛擬鍵會(huì)弱化成很細(xì)微的小點(diǎn)。一旦你再次點(diǎn)擊 status bar和navigation bar 的所在區(qū)域,他們就會(huì)再次完全顯現(xiàn)。這種方式的好處是status bar和navigation bar并沒有消失,仍然在界面上,但是它們的細(xì)節(jié)變暗了、模糊了。
View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
保持整個(gè)View穩(wěn)定, 常跟bar 懸浮, 隱藏共用, 使View不會(huì)因?yàn)镾ystemUI的變化而做layout
View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
狀態(tài)欄隱藏(導(dǎo)航欄仍然顯示)。跟WindowManager.LayoutParams.FLAG_FULLSCREEN有相同的效果(其實(shí)不同,因?yàn)樵摌?biāo)志下statusbar的高度還是會(huì)存在,不算真正意義上的全屏),同時(shí)在使用ActionBar的FEATURE_ACTION_BAR_OVERLAY時(shí),啟用SYSTEM_UI_FLAG_FULLSCREEN 會(huì)將ActionBar隱藏;該標(biāo)志一般適用于短期的全屏狀態(tài)而不是長期。
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
狀態(tài)欄上浮于Activity
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
暫時(shí)隱藏導(dǎo)航欄, 由于導(dǎo)航欄的重要性,當(dāng)產(chǎn)生細(xì)微的用戶交互后,比如單擊屏幕,都可能會(huì)導(dǎo)致navigation bar重新出現(xiàn),源于系統(tǒng)clear掉該標(biāo)志與SYSTEM_UI_FLAG_FULLSCREEN 標(biāo)志,同SYSTEM_UI_FLAG_IMMERSIVE 標(biāo)志一起使用可避免被clear
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION Level 16
導(dǎo)航欄上浮于Activity
View.SYSTEM_UI_FLAG_IMMERSIVE Level 19
Kitkat新加入的Flag, 沉浸模式, 跟SYSTEM_UI_FLAG_HIDE_NAVIGATION一起使用才有意義,可以避免系統(tǒng)在產(chǎn)生細(xì)微用戶交互時(shí)系統(tǒng)clear掉SYSTEM_UI_FLAG_HIDE_NAVIGATION標(biāo)志。如單獨(dú)使用SYSTEM_UI_FLAG_HIDE_NAVIGATION標(biāo)志時(shí)只需單擊屏幕,導(dǎo)航欄就會(huì)重新出現(xiàn);如果同時(shí)使用該標(biāo)志,則不會(huì)出現(xiàn),但用戶在導(dǎo)航欄區(qū)域仍然可以主動(dòng)呼出。呼出后,對(duì)應(yīng)的標(biāo)志會(huì)被清除。
View.SYSTEM_UI_FLAG_IMMERSIVE_STIKY Level 19
需要跟SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 或者 SYSTEM_UI_FLAG_FULLSCREEN 一起使用。當(dāng)單獨(dú)使用上面的標(biāo)志時(shí),任何用戶交互會(huì)導(dǎo)致導(dǎo)航欄重新出現(xiàn),從頂部向下滑動(dòng)會(huì)重新呼出狀態(tài)欄,這些操作會(huì)導(dǎo)致這些標(biāo)志被clear掉。如果同時(shí)指定SYSTEM_UI_FLAG_IMMERSIVE_STIKY 標(biāo)志,那么對(duì)應(yīng)標(biāo)志將不會(huì)被清除,且呼出隱藏的bar后會(huì)自動(dòng)再隱藏掉
總結(jié)
只有Aos 4.4 API 19 KitKat
以上版本才支持沉浸式狀態(tài)欄!