沉浸式狀態(tài)欄

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

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

怎么給狀態(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);
}

具體的實現(xiàn)在PhoneWindow類中,這里不再深入。既然方法都有了,那么直接調(diào)用就行了。這里我們在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,因為只有滿足條件的SDK版本才能找到該方法;與此同時,在設(shè)置狀態(tài)欄顏色的同時,API文檔 告訴我們還需要同步設(shè)置WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS這個Window Flag,并且需要保證WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS這個Window Flag沒有被設(shè)置。否則,不會生效

在調(diào)用任何一個不熟悉的方法時,請首先仔細閱讀一下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屬性;
  如果因為某種原因,不從Material Theme中繼承,那么就只能老老實實地指定特定的屬性不能偷懶,這些屬性包括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必須指定,因為它不再有默認(rèn)的指向android:colorPrimaryDark;此外,android:windowDrawsSystemBarBackgroundstrue必不可少;就像上面使用setStatusColor方法時需要注意的那樣,這個屬性相當(dāng)于添加了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS(當(dāng)然你也可以不在Theme中指定這個屬性,使用如上代碼那種方式添加Window Flag);而從Material Theme中繼承時沒有那樣做,是因為Material Theme中它默認(rèn)值為true

注意,上面Theme的聲明,對應(yīng)的資源文件應(yīng)該在values-v21文件夾下。因為不管是相應(yīng)的屬性,還是對應(yīng)的Material Theme都是至少API 21才能使用的

兼容低版本

OK,到此為止,我們所討論的都是基于API 21以上的。如果低版本該怎么辦?低版本的系統(tǒng)是不支持給狀態(tài)欄著色的,但卻可以通過 透明狀態(tài)欄+透明背景顏色 來實現(xiàn)相同的效果;廢話不多說,來看實現(xiàn)。

將系統(tǒng)狀態(tài)欄設(shè)置為透明

這是第一步。可以通過代碼方式

  getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

或者Theme Attribute的方式

  <item name="android:windowTranslucentStatus">true</item>
設(shè)置對應(yīng)背景顏色

接下來,就是背景顏色的設(shè)置。首先需要將ActionBar或者ToolBar的背景顏色設(shè)置為我們需要的顏色,具體如何設(shè)置不再深入,請自行研究(這里,如果沒有使用到ActionBar或者ToolBar,這一步可直接略過)。

其次,設(shè)置Activity根布局的背景顏色為一致的顏色;Just a piece of cake!

最后,我們還需要做一個調(diào)整。當(dāng)設(shè)置了狀態(tài)欄為透明后,Activity會相當(dāng)于一個FullScreen的全屏設(shè)置,窗口會占滿整個屏幕,整體的內(nèi)容會往上移動一段狀態(tài)欄高度的距離,這樣就會導(dǎo)致狀態(tài)欄覆蓋到我們的內(nèi)容。這時,我們需要在根布局上設(shè)置android:fitsSystemWindows="true",這樣系統(tǒng)會幫我們重新調(diào)整窗口的位置避免出現(xiàn)覆蓋的情況(無非就是給我們的窗口加上一個padding值);

注意,上面透明欄+背景色的方式只適用于API 19以上,因為這個版本以上的系統(tǒng)才支持透明化狀態(tài)欄,所以,19以下的系統(tǒng)不支持沉浸式狀態(tài)欄

其實系統(tǒng)的導(dǎo)航欄在API 19以上同狀態(tài)欄一樣也支持透明化和設(shè)置背景顏色,但這不是本文內(nèi)容

關(guān)于透明化狀態(tài)欄

上面說到android:windowTranslucentStatus可用于API 19以上的版本透明化狀態(tài)欄;但請注意,在19版本和19版本以上該屬性生效時存在差異。具體表現(xiàn)如下(這里盜用stackoverflow上的一張圖說明)

n0aYT.png

上圖中,左邊為19版本的顯示效果,右邊為21版本的效果;我們可以從圖中看到比較明顯的差異。在19版本中,系統(tǒng)給SystemBar添加了一個漸變,而21版本的則是一個透明的純色。如果我們使用android:windowTranslucentStatus在21版本及以上來實現(xiàn)沉浸式的應(yīng)用,則最終效果將不會太理想;那么是不是就不能實現(xiàn)了呢?No!

21版本以上的透明系統(tǒng)欄需要使用android:statusBarColor = "@android:color/transparent"來實現(xiàn);這里android:windowTranslucentStatus肯定是為false的,因為這兩個屬性是不能同時生效的。但是由于android:windowTranslucentStatus屬性的禁用,狀態(tài)欄將不再會是浮在我們的window上。沒關(guān)系,我們可以通過下面的方法達到一樣的效果:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

其實設(shè)置android:windowTranslucentStatus屬性時,正是系統(tǒng)幫我們設(shè)置了上面的Flag;上面我們在DecorView上調(diào)用這個方法,但其實可以在任何一個可見的View上進行調(diào)用,效果是一樣的。下面再補充說明一下setSystemUiVisibility其他可用的標(biāo)志:

View.SYSTEM_UI_FLAG_VISIBLE Level 14 默認(rèn)標(biāo)記

View.SYSTEM_UI_FLAG_LOW_PROFILE Level 14
低功耗模式, 會隱藏狀態(tài)欄圖標(biāo), 在4.0上可以實現(xiàn)全屏。status bar和navigation bar的相關(guān)圖標(biāo)會被弱化,比如navigation bar的幾個虛擬鍵會弱化成很細微的小點。一旦你再次點擊 status bar和navigation bar 的所在區(qū)域,他們就會再次完全顯現(xiàn)。這種方式的好處是status bar和navigation bar并沒有消失,仍然在界面上,但是它們的細節(jié)變暗了、模糊了。

View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
保持整個View穩(wěn)定, 常跟bar 懸浮, 隱藏共用, 使View不會因為SystemUI的變化而做layout

View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
狀態(tài)欄隱藏(導(dǎo)航欄仍然顯示)。跟WindowManager.LayoutParams.FLAG_FULLSCREEN有相同的效果(其實不同,因為該標(biāo)志下statusbar的高度還是會存在,不算真正意義上的全屏),同時在使用ActionBar的FEATURE_ACTION_BAR_OVERLAY時,啟用SYSTEM_UI_FLAG_FULLSCREEN 會將ActionBar隱藏;該標(biāo)志一般適用于短期的全屏狀態(tài)而不是長期。

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
狀態(tài)欄上浮于Activity

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
暫時隱藏導(dǎo)航欄, 由于導(dǎo)航欄的重要性,當(dāng)產(chǎn)生細微的用戶交互后,比如單擊屏幕,都可能會導(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)生細微用戶交互時系統(tǒng)clear掉SYSTEM_UI_FLAG_HIDE_NAVIGATION標(biāo)志。如單獨使用SYSTEM_UI_FLAG_HIDE_NAVIGATION標(biāo)志時只需單擊屏幕,導(dǎo)航欄就會重新出現(xiàn);如果同時使用該標(biāo)志,則不會出現(xiàn),但用戶在導(dǎo)航欄區(qū)域仍然可以主動呼出。呼出后,對應(yīng)的標(biāo)志會被清除。

View.SYSTEM_UI_FLAG_IMMERSIVE_STIKY Level 19
需要跟SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 或者 SYSTEM_UI_FLAG_FULLSCREEN 一起使用。當(dāng)單獨使用上面的標(biāo)志時,任何用戶交互會導(dǎo)致導(dǎo)航欄重新出現(xiàn),從頂部向下滑動會重新呼出狀態(tài)欄,這些操作會導(dǎo)致這些標(biāo)志被clear掉。如果同時指定SYSTEM_UI_FLAG_IMMERSIVE_STIKY 標(biāo)志,那么對應(yīng)標(biāo)志將不會被清除,且呼出隱藏的bar后會自動再隱藏掉

總結(jié)

只有Aos 4.4 API 19 KitKat以上版本才支持沉浸式狀態(tài)欄!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,908評論 2 372

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