管理系統UI之二:隱藏Status Bar (Hiding the Status Bar)
本文將講解如何在不同android版本中隱藏status bar,隱藏狀態欄(或者是導航欄)可以讓內容得到更多的展示空間,從而提供一個更加沉浸式的用戶體驗。
下圖展示了status bar可見時app的樣子:
下圖展示了status bar隱藏之后app的樣子,注意我們有意讓actionbar也跟著不見了,我們認為,當status bar隱藏的時候,actionbar也應該是隱藏的。
一、在android4.0及以下版本中隱藏status bar
在android4.0及以下版本中,你可以通過設置WindowManager
的flag來隱藏status bar。有兩種方式來設置WindowManager
的flag,一是在java代碼中,二是在manifest中設置activity的theme。如果你的status bar是一直隱藏的話,在manifest中設置activity的theme是最好的方式。
<application ... android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"> ... </application>
設置activity的theme的優點如下:
.簡單不易出錯。
.UI切換更流暢。因為系統在實例化activity之前已經獲得了渲染UI所需要的信息。
當然你也可以在java代碼中設置WindowManager
的flag:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If the Android version is lower than Jellybean, use this call to hide // the status bar. if(Build.VERSION.SDK_INT < 16) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } setContentView(R.layout.activity_main); } ... }
當你設置了WindowManager
的flag,將一直保持該flag的效果,除非你重置了flag。之所以強調這點是因為下面要講的內容中會出現設置了某個狀態但是不一定一直該保持狀態。
但是在status bar切換隱藏和顯示狀態的同時,activity的界面會發生重新分配UI的情況,而系統在UI重繪時并沒有做到視覺上的連續,看起來有點卡頓的錯覺。為了防止這種情況發生,你可以使用FLAG_LAYOUT_IN_SCREEN。
注:至于如何使用,我也不知道,而且我個人認為難以起到實際效果。
二、在4.0以上版本隱藏status bar
在Android 4.1 (API level 16)
或者更高版本中,你可以使用setSystemUiVisibility()來隱藏status bar,
使用setSystemUiVisibility()設置UI flag比使用
WindowManager
的flag擁有更多的控制選項。
下面是用
隱藏statusbar的代碼:setSystemUiVisibility
View decorView = getWindow().getDecorView(); // Hide the status bar. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions); // Remember that you should never show the action bar if the // status bar is hidden, so hide that too if necessary. ActionBar actionBar = getActionBar(); actionBar.hide();
一旦UI Flag被清除(比如跳轉到另外的activity),你需要重新設置UI flag來隱藏system bar。參見:動態響應UI Visibility改變事件一文,這篇文章討論了如何監聽UI visibility的改變,以便在改變的同時讓app的界面也做必要的改變。
以下是使用setSystemUiVisibility
()方法時需要注意的地方:
.在不同的地方設置Ui flag是有區別的,如果你是在onCreate中設置UI flag隱藏system bar,當用戶點擊home鍵,system bar將重新出現,用戶重新回到這個activity的時候,onCreate是不會被調用的,所以system bar仍然是可見的。因此如果你想在activity切換回來的時候仍然保持system bar的狀態,最好是在onResume()或者onWindowFocusChanged()方法中設置UI flag。
.只有當調用setSystemUiVisibility()
的view是可見的setSystemUiVisibility()
才會起作用。
.界面的切換會導致setSystemUiVisibility()
的設置被清空
三、讓內容布局在status bar的背后
在 android4.1以及之后的版本,可以讓activity的內容部分顯示在status bar的背后,status bar不再影響到實際內容的空間擺放(以前實際內容總是在status bar下面),因此在status bar切換顯示狀態的時候,內容區域的大小就不會發生變化。要達到這種效果只需使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN標志(flag)。同時,你也有可能需要
SYSTEM_UI_FLAG_LAYOUT_STABLE
這個標志來幫助你的應用維持一個穩定的布局(這句話真他媽理解不能)。
因為內容區域在status bar之后,這個時候你就需要確保你的app不會被status bar擋住需要操作的區域,不過大多數情況下在布局文件中添加android:fitsSystemWindows
屬性(值為true)可以解決status bar擋住內容區域的問題,因為該設置可以調整viewGroup的padding,為系統控件預留一定的區域。對于絕大多數應用來說,這樣做已經足夠了。
注:既然我們反正都需要預留空間給status bar 為什么我們還需要將內容區域顯示在status bar的后面呢?這一般是為了滿足這種需求:
在一個顯示圖片的GridView中,當GridView滾動的時候,我們希望status bar背后是有內容在滾動的,但是當GridView滑到了頂端,我又希望GridView是沒有被status bar擋住的。
在一些情況下,你可能需要修改默認的padding大小來獲取合適的布局。為了控制內容區域的布局相對系統欄(它占據了一個叫做“內容嵌入”content insets
的區域)的位置,你可以重寫fitSystemWindows(Rect insets)
方法。當窗口的內容嵌入區域發生變化時,fitSystemWindows()
方法會被view的hierarchy調用,讓View做出相應的調整適應。重寫這個方法你就可以按你的意愿處理嵌入區域與應用的布局。
四、同步status bar與Action Bar的變化
在Android 4.1及以上的版本,為了防止在Action Bar隱藏和顯示的時候布局發生變化,你可以使用Action Bar的overlay模式。在Overlay模式中,Activity的布局占據了所有可能的空間,好像Action Bar不存在一樣,系統會在布局的上方繪制Aciton Bar。雖然這會遮蓋住上方的一些布局,但是當Action Bar顯示或者隱藏的時候,系統就不需要重新改變布局區域的大小。
要啟用Action Bar的overlay模式,你需要創建一個繼承自Action Bar主題的自定義主題,將android:windowActionBarOverlay
屬性設置為true。
設置SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
來讓你的activity使用的屏幕區域與設置SYSTEM_UI_FLAG_FULLSCREEN
時的區域相同。當你需要隱藏系統UI時,使用SYSTEM_UI_FLAG_FULLSCREEN
。這個操作也同時隱藏了Action Bar(因為 windowActionBarOverlay="true"),當同時顯示與隱藏ActionBar與狀態欄的時候,使用一個動畫來讓他們相互協調。