问题

  • 在实际开发过程中,弹出对话框之前是沉浸式布局,但是弹出对话框之后,持有对话框的Activity显示了状态栏,用户体验很差,所以总结一下沉浸式体验

沉浸式

  • Android 沉浸式体验本质就是全屏化,整个屏幕显示都是服务内容,没有状态栏和导航栏,用户不会被系统元素打扰
  • 期望效果 应用程序的界面占据整个屏幕,用户通过手势来与系统控件进行交互

SYSTEM_UI_FLAG

FLAG

意义

SYSTEM_UI_FLAG_FULLSCREEN

隐藏系统状态栏

SYSTEM_UI_FLAG_HIDE_NAVIGATION

隐藏系统导航栏

SYSTEM_UI_FLAG_LAYOUT_SCREEN

状态栏悬浮于Activity上

SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

导航栏悬浮于Activity之上

SYSTEM_UI_FLAG_LAYOUT_STABLE

保持系统UI稳定,不会随着SystemUI的变化而变化

SYSTEM_UI_FLAG_IMMERSIVE

沉浸模式

SYSTEM_UI_FLAG_IMMERSIVE_STICKY

沉浸模式且状态栏和导航栏出现片刻之后会自动隐藏

eg:

  • 全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

沉浸式体验_全屏

  • 退出全屏
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

setSystemUiVisibility() 参数

参数

意义

View.SYSTEM_UI_FLAG_VISIBLE

显示状态栏

View.INVISIBLE

隐藏状态栏

View.SYSTEM_UI_FLAG_FULLSCREEN

Activity全屏显示,且状态栏被覆盖掉

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Activity全屏显示,但是状态栏不会被覆盖掉,而是正常显示,只是Activity顶端布 局会被覆盖住

View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

状态栏将布局顶部盖住

View.SYSTEM_UI_LAYOUT_FLAGS

全屏显示

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

隐藏虚拟按键

View.SYSTEM_UI_FLAG_LOW_PROFILE

低电量模式下,状态栏的某些图标会被隐藏

eg:

  • 隐藏状态栏和actionbar
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN)
getSupportActionBar().hide();

沉浸式体验_UI_02

  • 状态栏透明 (5.0以上的系统才会支持需要增加判断)
getWindow().getDecorView().setSystemUIVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setStatusBarColor(Color.TRANSPARENT);
getSupportActionBar().hide();

沉浸式体验_全屏_03

  • 导航栏透明
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

沉浸式体验_全屏_04

沉浸式体验

  • 沉浸式体验不仅仅需要隐藏状态栏,导航栏也需要一起隐藏掉
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
getSupportActionBar().hide();
  • 但是上述方法在Google文档中有说明:
  • 用户触摸屏幕任何位置都会导致设置的flag被清除了,不同地方设置UI Flag 效果会有不同的影响,在onResume()或者onWindowFocusChanged()函数中设置flag永久生效
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().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);
}
}

沉浸式体验_全屏_05

  • 状态栏文字颜色有时候也需要修改
//谷歌原生方法
private static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {
View decor = activity.getWindow().getDecorView();
if (dark) {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
  • 注意
  • 该方法会带上FULL_SCREEN, 默认为全屏模式,需要在根布局中设置FitsSystemWindows=“true”
View content = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);
if (content != null && !isUseFullScreenMode()) {
content.setFitsSystemWindows(true);
}

注意

  • 状态栏是可能会有自己的背景色的
//设置为透明色
getWindow().setStatusColor(Color.TRANSPARENT);
  • 一般一个Activity中有四个Tab页,那么在Activityy中设置的全屏模式,四个Fragment都是全屏模式,如果某一个Fragment不需要全屏模式,就要在Fragment 中添加一个状态栏的高度的View
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);