能夠造成SystemUI Flag被系統自動清除的交互分類
- 觸摸屏幕任何位置
- 頂部下拉狀態欄
- 底部上拉導航欄
- Window的變化(如:跳轉到其他界面、彈出鍵盤等)
SystemUI Flag 相關特性詳解
-
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:(>=api16)
作用是隱藏系統NavigationBar。
但是用戶的任何交互,都會導致此Flag被系統清除,進而導航欄自動重新顯示,同時View.SYSTEM_UI_FLAG_FULLSCREEN也會被自動清除,因此StatusBar也會同時顯示出來。 -
View.SYSTEM_UI_FLAG_FULLSCREEN:(>=api16)
作用是隱藏StatusBar。
和WindowManager.LayoutParams.FLAG_FULLSCREEN有相同視覺效果。不同在於,此Flag一般用在暫時需要全屏的情形(如:閱讀應用,全屏視頻等),以便讓用戶的注意力暫時集中在內容上,而如果只是簡單的需要一直停留在全屏狀態(如:遊戲應用),使用WindowManager.LayoutParams.FLAG_FULLSCREEN則是更好的選擇。
此Flag會因爲各種的交互(如:跳轉到其他應用,下拉StatusBar,彈出鍵盤)的發送而被系統清除。 -
View.SYSTEM_UI_FLAG_IMMERSIVE:(>=api19)
作用:避免某些用戶交互造成系統自動清除全屏狀態。- View.SYSTEM_UI_FLAG_IMMERSIVE和View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY的使用主要是爲了當設置全屏模式時,避免某些用戶交互造成系統自動清除全屏狀態。
- 當使用View.SYSTEM_UI_FLAG_HIDE_NAVIGATION隱藏導航欄時,配合此特性,只有第三、四種操作會導致導航欄的隱藏狀態被系統自動清除;否則,任何交互都會導致導航欄的隱藏狀態被系統自動清除。
- 此標識只有配合View.SYSTEM_UI_FLAG_HIDE_NAVIGATION纔有作用。
-
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY:(>=api19)
作用:避免某些用戶交互造成系統自動清除全屏狀態。同時Activity的部分內容也因此被StatusBar覆蓋遮擋。- 用View.SYSTEM_UI_FLAG_HIDE_NAVIGATION隱藏導航欄,配合使用此Flag,只有用戶的第四種操作會導致狀態欄或(和)導航欄的隱藏狀態被系統自動清除。否則任何交互都會導致相應狀態的清除。
- 此Flag只有配合SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION使用時纔會起作用。
-
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:(>=api16)
作用:在不隱藏導航欄的情況下,將Activity的顯示範圍擴展到導航欄底部。同時Activity的部分內容也因此被NavigationBar覆蓋遮擋。- 當使用此Flag時,設置fitSystemWindow=true的view,會被系統自動添加大小爲NavigationBar高度相同的paddingBottom。
- 當window設置WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION時,此Flag會被系統會自動添加。
-
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:(>=api16)
作用:在不隱藏StatusBar的情況下,將view所在window的顯示範圍擴展到StatusBar下面。同時Activity的部分內容也因此被StatusBar覆蓋遮擋。- 當使用此Flag時,設置fitSystemWindow=true的view,會被系統自動添加大小爲statusBar和ActionBar高度之和相同的paddingTop。
- 當window設置WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS時,此Flag會被系統會自動添加。
-
View.SYSTEM_UI_FLAG_LAYOUT_STABLE:
作用: 穩定佈局。當StatusBar和NavigationBar動態顯示和隱藏時,系統爲fitSystemWindow=true的view設置的padding大小都不會變化,所以view的內容的位置也不會發生移動。- 當使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN或SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION),同時view設置fitSystemWindow=true時,系統會爲此View自動設置padding。此padding的大小由View.fitSystemWindows(Rect)的Rect提供。一般情況下,當StatusBar和NavigationBar顯示時,paddingTop的大小爲StatusBar的高度。如果設置了getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY),paddingTop的大小則爲StatusBar和ActionBar的高度之和。paddingBottom的大小則爲NavigationBar的高度。當StatusBar和NavigationBar被隱藏時,View的padingBottom和paddingTop的大小就變成了0, 因此StatusBar和NavigationBar的顯示和隱藏造成的padding變化,進而View內容的位置變化,從而造成位置閃動的視覺效果,影響體驗。
使用SYSTEM_UI_FLAG_LAYOUT_STABLE的作用便是當StatusBar和NavigationBar的顯示和隱藏,系統爲View設置的padding都不會變化,因此View內容的位置不會變化,此即爲穩定佈局。
-. (SYSTEM_UI_FLAG_FULLSCREEN |SYSTEM_UI_FLAG_LAYOUT_STABLE)時,
會同時隱藏Actionbar和StatusBar,但StatusBar所佔空間不會隱藏,只會變成空白。同時View所在window的顯示範圍也不會伸展到StatusBar所佔空間。若是加上SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,View所在window的顯示範圍則會伸展到StatusBar所在的空間。
同樣對NavigationBar如此操作,也會是一樣的效果。
- 當你設置了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN時,配合此特性,若此時設置或取消SYSTEM_UI_FLAG_FULLSCREEN,不會因爲StatusBar的顯示或隱藏不會造成內容view的不穩定。
- 當你設置了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,配合此特性,若此時設置或取消SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION,不會因爲StatusBar和導航欄的顯示或隱藏不會造成內容view的不穩定。
- 此特性不應該只配合SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION使用
- 使用WindowManager.LayoutParams.FLAG_FULLSCREEN(而不是使用SYSTEM_UI_FLAG_FULLSCREEN)來隱藏StatusBar是一個一直持續隱藏的狀態。這時你仍然可以使用SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE隱藏Actionbar,並且不會因爲ActionBar的顯示或隱藏而不穩定。
- 當使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN或SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION),同時view設置fitSystemWindow=true時,系統會爲此View自動設置padding。此padding的大小由View.fitSystemWindows(Rect)的Rect提供。一般情況下,當StatusBar和NavigationBar顯示時,paddingTop的大小爲StatusBar的高度。如果設置了getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY),paddingTop的大小則爲StatusBar和ActionBar的高度之和。paddingBottom的大小則爲NavigationBar的高度。當StatusBar和NavigationBar被隱藏時,View的padingBottom和paddingTop的大小就變成了0, 因此StatusBar和NavigationBar的顯示和隱藏造成的padding變化,進而View內容的位置變化,從而造成位置閃動的視覺效果,影響體驗。
fitSystemWindow
只有設置了View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION或View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,View的 fitSystemWindow=true纔會有效果。
WindowManager 相關特性詳解
-
WindowMananger.FLAG_TRANSLUCENT_STATUS: (>=api16)
- 半透明StatusBar,並且不會因用戶交互而被清除。
- 設置了此flag,系統會自動設置View.SYSTEM_UI_FLAG_LAYOUT_STABLE和View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-
WindowMananger.FLAG_FULLSCREEN:
- 用於隱藏StatusBar
- 使用此flag,系統會自動忽略輸入法的SOFT_INPUT_ADJUST_RESIZE的特性。
-
WindowMananger.FLAG_TRANSLUCENT_NAVIGATION:
1.半透明NavigationBar,並且不會因用戶交互而被清除。
2.設置了此flag,系統會自動設置View.SYSTEM_UI_FLAG_LAYOUT_STABLE和View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
最低版本支持:Android4.4 (api 19) -
WindowMananger.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS:
1.用於未StatusBar和NavigationBar設置背景顏色。
2.原理:將StatusBar和NavigationBar設置爲透明背景,並且將StatusBar和NavigationBar所在空間設置爲Window.getStatusBarColor() 和Window.getNavigationBarColor()方法獲得的顏色。
最低版本支持:Android5.0 (api 21)
SystemUI Flag引起的軟鍵盤變化
在使用SOFT_INPUT_ADJUST_RESIZE,
同時View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN或View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION時,當鍵盤彈出時,只會fitSystemWindow=true的view所佔區域會被resize,其他view將會被軟鍵盤覆蓋。
常用情形
- 隱藏狀態欄
代碼實例1
private fun hideStatusBar(){
layout.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
}
注意:用戶的第二、四類交互操作都會使系統自動清除狀態欄隱藏狀態(系統會自動取消View.SYSTEM_UI_FLAG_FULLSCREEN的設置)
代碼實例2
private fun hideStatusBar(){
var tag = (View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
layout.systemUiVisibility = tag
}
注意:用戶的第四類交互操作會使系統自動清除狀態欄隱藏狀態(系統會自動取消View.SYSTEM_UI_FLAG_FULLSCREEN的設置,但是不會取消View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);用戶的第二類操作會使狀態欄暫時顯示,延遲幾秒後自動消失。
代碼實例3
private fun hideStatusBar(on: Boolean) {
val winParams = window.attributes
val bits = WindowManager.LayoutParams.FLAG_FULLSCREEN
if (on) {//隱藏狀態欄
winParams.flags = winParams.flags or bits
} else {//顯示狀態欄
winParams.flags = winParams.flags and bits.inv()
}
window.attributes = winParams
}
注意:1.用戶任何交互操作都不會使系統自動清除狀態欄隱藏狀態;用戶的第二類操作會是狀態欄暫時顯示,延遲幾秒後自動消失。
2.使用此flag,系統會自動忽略輸入法的SOFT_INPUT_ADJUST_RESIZE的特性。
- 透明狀態欄
代碼實例1:半透明狀態欄
private fun translateStatusBar(on: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
var p = window.attributes
p.flags = p.flags or WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
window.attributes = p
}
}
注意:爲避免狀態欄遮擋View上的部分信息,需要爲View設置fitSystemWindow=true,或手動設置padding
代碼實例2:透明狀態欄
private fun translateStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = Color.TRANSPARENT
var tag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
layout.systemUiVisibility = tag
}
}
注意:
- Android的狀態欄的字體顏色默認爲白色,只有Android6.0以後才提供官方的API選擇黑色字體(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)。所以當6.0以下使用透明狀態欄時,若StatusBar下面的View的也爲白色背景時,則會造成看不到StatusBar的相關信息。
- 爲避免狀態欄遮擋View上的部分信息,需要爲View設置fitSystemWindow=true,或手動設置padding
- 隱藏導航欄
代碼實例1
private fun hideNavigationBar(){
layout.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}
注意:用戶的任何操作都會使系統自動清除此狀態。SYSTEM_UI_FLAG_HIDE_NAVIGATION被系統自動清除時會連帶清除SYSTEM_UI_FLAG_FULLSCREEN
代碼實例2
private fun hideNavigationBar(){
var tag = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_IMMERSIVE)
layout.systemUiVisibility = tag
}
注意:用戶的第三、四類交互操作會使系統自動清除此狀態;用戶的第二類操作會是狀態欄暫時顯示,延遲幾秒後自動消失
代碼實例3
private fun hideNavigationBar(){
var tag = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
layout.systemUiVisibility = tag
}
注意:用戶的第四類交互操作會使系統自動清除此狀態;用戶的第三類操作會是使導航欄暫時顯示,延遲幾秒後自動消失
- 全屏模式
代碼實例1:一般用於視頻播放的情形
private fun fullScreen(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
var tag = (View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABL)
layout.systemUiVisibility = tag
}
}
注意: 用戶的任何交互都會導致全屏狀態被系統清除
代碼實例2:一般用於沉浸閱讀的情形
private fun fullScreen(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
var tag = (View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_IMMERSIVE)
layout.systemUiVisibility = tag
}
}
代碼實例3::一般用於遊戲等嚴格沉浸的情形
private fun fullScreen(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
var tag = (View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
layout.systemUiVisibility = tag
}
}
- 修改SystemBar的顏色
代碼實例1
private fun setSystemBarColor(int color){
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS|WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = color
window.navigationBarColor = color
}