第一次在項目中要用到全屏功能的時候無從下手,然后就是去百度了。百度到的結果都是差不多的。不過直接把代碼貼過來的確是可以用的。但是除了知道怎么做之外還想去理解它,因為只有理解了才能舉一反三嘛。好在在后來的時候看到了官方的文檔,寫的非常詳細。
–> 我是官方文檔 <–
接下來開始正題
… … …
先給出一些名詞方便下面的講解
StatusBar
NavigationBar
SystemBar – StatusBar 跟 NavigationBar 的統稱
設置全屏主要分為兩種方式:
4.0 之前采用的方式4.0 之后新增的方式
4.0 以及之前設置全屏
因為 4.0 之前的系統已經很少了,所以這里就簡單的說一下。 有兩種方式可以實現全屏:
使用全屏的主題getWindow().addFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN);這種全屏方式是無法隱藏 NavigationBar 的(如果有 NavigationBar 的話),因為 NavigationBar 是在 4.0 以后才引入的。使用這種方式設置全屏的特點是,離開了 App 后再進入 App 時,依然處于全屏模式,只能清除掉全屏標志位才能退出全屏。
4.1 以及之后設置全屏
4.1 以及之后使用 View 的 setSystemUiVisibility()
來對 SystemBar 進行控制。 任何 View 都可以用來調用這個方法,只要它是可見狀態的。
下面先把要涉及到的 flag 分組列舉出來(所有的 flag 都是以 SYSTEM_UI_FLAG 作為前綴,所以下面將其省略)。
控制 SystemBar 相關:
FULLSCREENHIDE_NAVIGATIONLOW_PROFILE布局相關:
LAYOUT_SCREENLAYOUT_HIDE_NAVIGATIONLAYOUT_STABLE沉浸式相關 (4.4 引入):
IMMERSIVEIMMERSIVE_STICKY超前提示:
在離開 App 時,比如按了 home / 多任務鍵 會導致設置的控制 SystemBar 相關的 flag 被清除,而其他設置的 flag 不會受到影響。
FULLSCREEN
雖然寫的是 Fullscreen ,但其實只是隱藏 StatusBar。
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDecorView = getWindow().getDecorView(); mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); // Google 建議隱藏 StatusBar 時也將 ActionBar 一起隱藏 getActionBar().hide();}
1234567891012345678910
看圖可以得出以下幾點:
點擊屏幕 StatusBar 不會顯示出來從屏幕上邊緣往下滑可以讓 StatusBar 重新顯示點擊 home / 多任務鍵再返回 App 時 StatusBar 重新顯示了出來,印證了超前提示里所說的。而且 StatusBar 在顯示出來以后不會自動隱藏,這一點跟在 4.1 之前設置的全屏方式不一樣,因為設置的 FULLSCREEN flag 已經被清除了,如果想重新隱藏,需要重新設置該 flag。StatusBar 的顯示 / 隱藏會使 ImageView 大小發生了變化為了防止布局大小不會因為 StatusBar 的顯示 / 隱藏發生變化,有兩種 flag 可供選擇:
1.LAYOUT_STABLE
mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
123123這里有一點需要注意:設置多個標志位時要用 | 連接起來,不能多次調用 setSystemUiVisibility。如:
mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
1212這樣的結果就是只有最后一次設置的 flag 生效,而之前設置的標志位會被清除。也就是說上面的代碼中只設置了 LAYOUT_STABLE 而 FULLSCREEN 被清除了。所以如果想清除之前設置的所有 flag ,mDecorView.setSystemUiVisibility(0) 就可以了

這次布局并沒有延伸到 StatusBar 底下,所以大小也就不會受到它的影響
2.LAYOUT_FULLSCREEN
mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
123123
可以看到布局已經延伸到了 StatusBar 底部。
HIDE_NAVIGATION
protected void onCreate(Bundle savedInstanceState) { mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}
1234512345Google 建議隱藏 NavigationBar 的同時將 StatusBar 一起隱藏。

與隱藏 StatusBar 時不同的是,隱藏了 NavigationBar 以后,點擊屏幕的任何位置都會導致設置的所有控制 SystemBar 相關的 flag 被清除,所以 SystemBar 重新顯示了出來。這里還需要注意的在這種模式下點擊屏幕點擊事件會被屏蔽,要等到 SystemBar 顯示出來以后再次點擊,事件才會傳遞到我們的布局中。
與 LAYOUT_FULLSCREEN 類似的是, LAYOUT_HIDE_NAVIGATION 可以讓布局內容延伸到 NavigationBar 的底部。
因為離開 App 后控制 SystemBar 相關的 flag 會被清除,所以可以按需在 onResume()
或者 onWindowFocusChanged()
中重新設置它們。
LOW_PROFILE
protected void onCreate(Bundle savedInstance) { mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LOW_PROFILE);}
12341234作用是減少 StatusBar 中的圖標并使其變暗,將 NavigationBar 中的按鈕減弱成 3 個點。 知乎在閱讀文章的時候就使用到了這個模式

可以看到,在向上滑動內容的時候 SystemBar 的內容被弱化了,這樣可以減少其他元素對閱讀者的干擾。
設置沉浸式模式(4.4 之后引入)
沉浸式模式是在 4.4 之后才引入的
IMMERSIVE
mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE);
12345671234567
可以看到設置了該 flag 以后,點擊屏幕不會讓 SystemBar 顯示出來。呼出 SystemBar 的方式是在屏幕上邊緣向下滑動,在呼出 SystemBar 后,控制 SystemBar 相關的 flag 會被清除。
IMMERSIVE_STICKY
mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
12345671234567跟 IMMERSIVE 不同的是,在該模式下呼出的 SystemBar 會在短暫的顯示后重新隱藏。并且在 SystemBar 顯示出來的時候點擊屏幕中心會立刻讓 SystemBar 重新隱藏。所以在模式下呼出 SystemBar 并不會清除控制 SystemBar 相關的 flag。但是離開 App 時控制 SystemBar 相關的 flag 還是會被清除。

所以在回到 App 的時候需要重新設置:
@Overridepublic void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}}
123456789101112123456789101112監聽 SystemBar 的變化
通常情況下我們需要能夠控制 SystemBar 的顯示與隱藏,這個時候就需要監聽 SystemBar 的狀態。 通過 OnSystemUiVisibilityChangeListener 就可以對 SystemBar 的狀態進行監聽。
protected void onCreate(Bundle savedInstance) { mDecorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { if (visibility == 0) { // SystemBar 處于顯示狀態 } else { // SystemBar 處于隱藏狀態 } }});
12345678910111234567891011上面的代碼展示了如何對 SystemBar 的狀態進行監聽。 當 SystemBar 的顯示狀態發生變化時,onSystemUiVisibilityChange() 方法就會被調用。但是有一個例外,設置 IMMERSIVE_STICKY 后將 SystemBar 呼出并不會觸發該監聽器。
下面具體解釋一下 onSystemUiVisibilityChange(int visibility) 方法
onSystemUiVisibilityChange(int visibility) 方法中的 visibility 參數表示的是 LOW_PROFILE、FULLSCREEN 跟HIDE_NAVIGATION 這三個 flag 的值的和。
FULLSCREEN(4)HIDE_NAVIGATION(2)LOW_PROFILE(1)括號中的數字是它們的值。
為什么 visibility 只是表示這 3 個 flag 的和呢?因為只有這 3 個值是跟控制 SystemBar 相關的。也就是說從visibility
的值就可以只知道我們設置了哪些 flag。比如當 visibility
等于 4 時,說明設置了 FULLSCREEN 這個 flag;如果 visibility
等于 7 則說明 3 種 flag 都設置了。所以當 visibility
為 0 時表示沒有設置任何控制 SystemBar 的 flag,也就說明了 SystemBar 當前處于顯示狀態。
那為什么 visibility
的值會是它們三個的和呢?因為我們在設置 flag 的時候是用 | 將多個 flag 連接在一起的, | 就相當于把它們的值加起來。
下面給出一個 Demo ,功能是點擊圖片時進入 / 退出全屏
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @BindView(R.id.image) ImageView mImage; View mDecorView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); mDecorView = getWindow().getDecorView(); // 讓圖片鋪滿屏幕 mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } @OnClick(R.id.image) public void onClick() { // 只需要處理隱藏 SystemBar 就行了,因為顯示 SystemBar 是由系統完成的 hideSystemUI(); } private void hideSystemUI() { mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); } private void showSystemUI() { mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); }}
12345678910111213141516171819202122232425262728293031323334353637383940414243441234567891011121314151617181920212223242526272829303132333435363738394041424344
這里有一個問題,如果點擊稍微快一點的話就會出現只隱藏 StatusBar 而沒有隱藏 NavigationBar 的情況。如果有哪個小伙伴知道的話請告知一下。
希望這篇文章能給大家帶來一點點幫助。
頂8