沉浸式狀態(tài)欄

何謂沉浸式狀態(tài)欄##

說白了,沉浸式狀態(tài)欄本質(zhì)上就是給系統(tǒng)狀態(tài)欄著色。當(dāng)這個(gè)顏色和我們Activity中的ToolBar或者ActionBar所使用的背景顏色一致時(shí)就會(huì)有沉浸式的效果。

怎么給狀態(tài)欄著色##

那么我們要怎么樣才能給系統(tǒng)狀態(tài)欄著色呢?谷歌后知后覺,終于在API 21Window類中添加了相應(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 Themeandroid:statusBarColor屬性的值默認(rèn)使用android:colorPrimaryDark屬性指定的值;所以我們也可以僅僅指定android:colorPrimaryDark屬性;
  如果因?yàn)槟撤N原因,不從Material Theme中繼承,那么就只能老老實(shí)實(shí)地指定特定的屬性不能偷懶,這些屬性包括android:statusBarColorandroid: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:windowDrawsSystemBarBackgroundstrue必不可少;就像上面使用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上的一張圖說明)

n0aYT.png

上圖中,左邊為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)欄!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容