文章目录
前言
Android HMI开发中,需要控制状态栏、导航栏的显示隐藏,该文介绍在不同版本中,如何实现状态栏、导航栏的显示/隐藏控制,以及沉浸态的设置。
一、Android 10(API 29)及以下版本
使用setSystemUiVisibility的方法控制控制状态栏、导航栏
Activity或者系统View均可以使用
状态栏、导航栏显示控制
代码如下(以Activity为例):
int flag = getWindow().getDecorView().getSystemUiVisibility();
if (needHideStatusBar) {
// 隐藏状态栏
flag = flag | View.SYSTEM_UI_FLAG_FULLSCREEN;
// 避免用户点击屏幕操作拉起状态栏
flag = flag | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
else if (needShowStatusBar) {
// 显示状态栏
flag = flag & (~View.SYSTEM_UI_FLAG_FULLSCREEN);
}
if (needHideNaviBar) {
// 隐藏导航栏
flag = flag | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
// 避免用户点击屏幕操作拉起状态栏
flag = flag | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
else (needShowNaviBar) {
// 显示导航栏
flag = flag & (~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
getWindow().getDecorView().setSystemUiVisibility(flag);
注意以下几点:
1、仅获取focus的画面设置有效
2、setSystemUiVisibility() 方法仅在调用它所在的画面(Activity或者View)可见时有效。
3、离开画面后系统清除使用 setSystemUiVisibility() 设置的标志,如果需要保留设置,建议在onWindowFocusChanged中进行设置
沉浸态设置
一般情况下,状态栏或者导航栏显示时,会将我们的布局页面向反方向挤走
比如状态栏显示时,我们的布局页面会向下移动状态栏高度的距离;状态栏隐藏后,布局再上移回来
当设置沉浸态后,布局会显示在状态栏下层,不受状态栏显示/隐藏的影响
同样通过setSystemUiVisibility的方法设置沉浸态
代码如下(以Activity为例):
int flag = getWindow().getDecorView().getSystemUiVisibility();
// 状态栏沉浸态
flag = flag | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
// 导航栏沉浸态
flag = flag | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getWindow().getDecorView().setSystemUiVisibility(flag);
注意:
状态栏或导航栏显示时,才存在“沉浸态”效果,可以和上面设置状态栏/导航栏显示的flag一起设置。
二、Android 11(API 30)及以上版本
状态栏、导航栏显示控制
使用WindowInsetsController的方法进行设置
Activity设置:
if (Build.VERSION.SDK_INT >= 30) {
WindowInsetsController controller = getWindow().getDecorView().getWindowInsetsController();
if (null != controller) {
// 显示、隐藏状态栏:
controller.show(WindowInsets.Type.statusBars());
controller.hide(WindowInsets.Type.statusBars());
// 显示、隐藏导航栏
controller.show(WindowInsets.Type.navigationBars());
controller.hide(WindowInsets.Type.navigationBars());
}
}
系统View设置:
if (Build.VERSION.SDK_INT >= 30) {
WindowInsetsController controller = getWindowInsetsController();
if (null != controller) {
// 显示、隐藏状态栏:
controller.show(WindowInsets.Type.statusBars());
controller.hide(WindowInsets.Type.statusBars());
// 显示、隐藏导航栏
controller.show(WindowInsets.Type.navigationBars());
controller.hide(WindowInsets.Type.navigationBars());
}
}
沉浸态设置
Activity设置:
// 沉浸态(状态栏和导航栏覆盖在Activity上层):
getWindow().setDecorFitsSystemWindows(false);
// 非沉浸态(状态栏和导航栏将Activity挤走):
getWindow().setDecorFitsSystemWindows(true);
View设置:
通过setFitInsetsTypes设置
WindowManager vm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mLp;
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, // 宽
ViewGroup.LayoutParams.MATCH_PARENT, // 高
2250, // type,也就是层级Id,这里仅测试用
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
mLp.gravity = Gravity.TOP | Gravity.START;
// 打开沉浸态
mLp.setFitInsetsTypes(0);
vm.addView(view, mLp);
使用过程中遇到的问题整理
Android12中,没有删除setSystemUiVisibility的方法,只是将其标记为已废弃,依旧可以使用setSystemUiVisibility的方法进行设置。
但是在Android12实际使用过程中,发现使用setSystemUiVisibility设置存在一些问题
问题:
Activity本身需要显示导航栏,新打开一个系统View,隐藏导航栏
分别在Activity和View显示时,通过setSystemUiVisibility设置导航栏的显示隐藏
发现系统View关闭后,Activity正常显示且获取了focus,导航栏没有显示出来,但是点击导航栏位置,是可以正常点击到的。
解决方法:
1、使用setFitInsetsTypes的方法设置导航栏显示/隐藏
2、在画面已经获取到focus或者onWindowFocusChanged回调中,调用setFitInsetsTypes方法