與Status Bar和Navigation Bar相關的一些東西

與StatusBar和NavigationBar相關的東西有兩種,一是控制它們的顯示與隱藏,二是控制它們的透明與否及背景。 git

在2.3及之前,StatusBar只能顯示與隱藏,即全屏模式,經過WindowManager.LayoutParams.FLAG_FULLSCREEN來實現: github

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

並可經過如下Flag使Activity的佈局可使用整個屏幕,狀態欄會顯示到Activity上方並遮蓋部分佈局 函數

getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

在3.0(API 11)中,添加了一個重要的方法:setSystemUiVisibility(int),用於控制包括Status Bar在內的一些窗口裝飾元素的顯示,並添加了View.STATUS_BAR_VISIBLE和View.STATUS_BAR_HIDDEN兩個Flag用於控制Status Bar的顯示與隱藏,但在4.0(API 14)中廢棄了。 佈局

在4.0(API 14)中,Andorid引入了Navigation Bar,並添加了一個Flag:SYSTEM_UI_FLAG_HIDDEN_NAVIGATION用於控制Navigatoin Bar的顯示。3.0中被棄用的View.STATUS_BAR_VISIBLE被View.SYSTEM_UI_VISIBLE替代,View.STATUS_BAR_HIDDEN被View.SYSTEM_UI_LOW_PROFILE替代,View.SYSTEM_UI_LOW_PROFILE不會使Status Bar和Navigation Bar消失,而是會使它們變暗,下降它們對視覺的干擾,使用戶能夠專一於應用的內容,但仍可響應用戶的交互,當和它們的交互發生時,會退出Low Profile的狀態。 spa

在4.1(API 16)中,對Status Bar和Navigation Bar的控制進一步加強,引入了View.SYSTEM_UI_FLAG_FULLSCREEN,和View.SYSTEM_UI_HIDDEN_NAVIGATION分別控制Status Bar和Navigation Bar的顯示。並同時引入了另外三個Flag:View.SYSTEM_UI_FLAG_LAYOUT_STABLE、View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION。 3d

顯示System UI: code

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

隱藏System UI 視頻

getWindow().getDecorView().setSystemUiVisibility(
          View.SYSTEM_UI_FLAG_FULLSCREEN
        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_IMMERSIVE
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

經過上面那段View.SYSTEM_UI_FLAG_FULLSCREEN、View.SYSTEM_UI_FLAG_HIDE_NAVIGATION相關的代碼實現的全屏模式,能夠隱藏掉Status Bar和Navigation Bar,可是這些都是很重要的功能,尤爲是Navigation Bar,對於只有虛擬按鍵的手機,若是隱藏掉Navigation Bar,連切換程序都作不到,因此,當用戶和手機有任何交互的時候都會從新顯示Status Bar和Navigation Bar,這被稱爲LEAN BACK模式。這很適合視頻播放的場景,但對於其餘一些場景可能就不適合了,好比讀書。 繼承

因此,在4.4(API 19)中引入了沉浸模式View.SYSTEM_UI_FLAG_IMMERSIVE和View.SYSTEM_UI_FLAG_IMMERSIVE_STICK。在IMMERSIVE模式中,用戶的普通交互並不會使系統退出IMMERSIVE模式,若是要退出IMMERSIVE模式,須要在屏幕的頂部或底部向內滑動。這可使用戶專一於內容,但退出方式並不像LEAN BACK模式那麼明顯,因此在第一次進入IMMERSIVE時,系統會彈出一個UI提醒退出的方法。SYSTEM_UI_FLAG_IMMERSIVE等須要和SYSTEM_UI_FLAG_FULLSCREEN、SYSTEM_UI_FLAG_HIDE_NAVIGATION一塊兒使用。 get

IMMERSIVE_STICKY和IMMERSIVE的區別是,在IMMERSIVE中,用戶從屏幕頂部或底部向內滑動時會退出IMMERSIVE模式,須要手動控制再次進入IMMERSIVE模式,而在IMMERSIVE_STICKY模式中,一樣的操做只會使系統以半透明方法顯示System UI方便用戶操做,並會在一段時間後自動隱藏,此時並不會引發onSystemUiVibilityChanged的調用。

能夠看到,關於全屏,關於System UI的控制,若是想有好的體驗,仍是有不少細節須要處理的,不過幸虧,chrisbanes大神寫了一個類來處理這些細節:https://gist.github.com/chrisbanes/73de18faffca571f7292

除了控制System UI的顯示和隱藏外,還可使它們變成透明的,在4.4(API 19)中還引入了WindowManager.LayoutParams.FLAG_TRANSUCENT_STATUS和WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION用於控制System UI變透明,這兩個Flag分別對應於windowTranslucentStatus和windowTranslucentNavigation兩個attr,並同時提供了相應的Theme(這些Theme都沒有ActionBar),當使用這兩個Flag時,SYSTEM_UI_FLAG_LAYOUT_STABLE、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION會被自動添加。

當System UI變透明後,Activity的UI佔據整個屏幕,System UI覆蓋在Activity的UI上面,對於通常的應用,雖然System UI透明瞭,但會發現效果並無那麼好,由於ActionBar仍是在Status Bar下面,Status Bar變爲透明後會透出Activity的UI,通常狀況下這部分UI和ActionBar放到一塊兒並非那麼協調。能夠設置窗口的背景和ActionBar的色調一致,但會引發OverDraw,而且若是指定的佈局撐不滿全屏呢?

咱們知道,Activity頂部的佈局是DecorView,而DecorView繼承自FrameLayout,因此能夠添加兩個View到DecorView中,佔據Status Bar和Navigation Bar的位置,並設置它們的背景使其與ActionBar相配,但這須要計算Status Bar和Navigation Bar的大小,而且須要判斷Navigation Bar的位置(Bottom or Right)。正好,也有人作了這樣的事:https://github.com/jgilfelt/SystemBarTint

不管是LEAN_BACK模式仍是IMMERSIVE模式,都使用到了4.1中引入的三個Flag:SYSTEM_UI_FLAG_LAYOUT_STABLE、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,它們的用處並不像SYSTEM_UI_FLAG_FULLSCREEN那麼明顯,並且名稱還很類似,要了解它們的用處,須要先了解一個內容邊襯區的概念(ContentInset)及一個重要的函數View.fitSystemWindows。

默認狀況下,應用程序窗口在Status Bar下面,系統已經處理好了應用窗口的顯示,咱們不須要關心Inset和fitSystemWindow,但有一些狀況就要咱們本身處理了。

當使用了Translucent System UI或SYSTEM_UI_FLAG_FULLSCREEN等時,Activity的UI能夠顯示到System UI下面,System UI在顯示時可能會蓋住Activity的UI,因此可能須要處理這樣的狀況,這就須要知道System UI會佔用的空間大小是多少,這個大小就是內容邊初區(ContentInset),系統會經過fitSystemWindows(Rect)來通知咱們,咱們能夠經過這個方法調整咱們的內容顯示。

還有一個方法是View.setFitSystemWindows(boolean),用於設置是否使用系統默認的fitSystemWindows實現。系統的默認實現會消耗掉內容邊襯區空間的佔用,算到View的Padding裏面,並返回true,不然什麼也不作返回false,當返回false時,會繼續調用View Hierarchy中其餘View的fitSystemWindows,直到某一個View中返回true,調用順序是深度優先。若是咱們決定本身處理System UI的空間佔用,能夠重寫VIew的fitSystemWIndows並返回true,若是本身只是作些處理,仍想調用系統的默認實現,要記得調用super.fitSystemWindows並返回false。

接下來就能夠說SYSTEM_UI_FLAG_LAYOUT_STABLE等的做用了。在使用View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION時,Status Bar和Navigation Bar都會隱藏,Activity的UI佔據整個屏幕,當System UI再次顯示時,應用程序窗口會被Resize,爲System UI騰出空間,這會引發屏幕的跳動,這三個Flag的做用就在於此,SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION要和SYSTEM_UI_FLAG_LAYOUT_STABLE一塊兒使用,用於控制當Status Bar或Navigation Bar顯示或隱藏時,Activity的UI是否會被Resize,當使用這三個Flag時,Activity會佔用整個屏幕空間,並經過fitSystemWindows傳入的Insets標明Insets的大小(對於SYSTEM_UI_FLAG_FULLSCREEN會同時包含ActionBar的大小),咱們能夠根據這個Insets的大小調整內容的顯示,若是給ContentView設置fitSystemWindows爲true,會自動把Iinset轉化爲padding。

有幾點須要注意的是:

  1. 當調用fitSystemWindows時是深度優先遍歷
  2. setSystemUiVibility是View中定義的方法,因此咱們能夠用Activity佈局中任意一個View控制System UI,只要這個View不是Gone狀態,系統會組合全部可見View的設置,因此通常狀況下會直接對DecorView進行設置。
  3. 當切換程序時,系統會清除SYSTEM_UI_FLAG_FULLSCREEN等Flag,因此須要經過setSystemUiVisibilityListener、onWindowFocudChanged等方法控制應用的狀態。
  4. 魅族MX2,Flyme 3.5系統,Android 4.4.4,Immersive模式沒法退出,不過這個機型有實體按鍵,因此影響不大,沒法從頂部下拉或底部滑動退出全屏,由於Flyme系統自己就支持在全屏時拉出狀態欄或調出任務切換,系統設置中也能夠關閉這個功能。

參考:https://www.youtube.com/watch?v=cBi8fjv90E4&feature=youtu.be

相關文章
相關標籤/搜索