【Android HMI开发】状态栏和导航栏的控制


前言

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方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值