Android 11环境下如何彻底隐藏/禁用导航栏与状态栏?
Android 11下彻底隐藏/禁用导航栏与状态栏的解决方案
针对你遇到的普通沉浸式模式滑动后系统栏仍会弹出的问题,以下是几种可行的解决方向:
1. 设备所有者/配置文件所有者模式(最彻底的系统级限制)
Android 11中,只有拥有设备所有者或配置文件所有者权限的应用,才能真正禁用导航栏和状态栏。这种方式通过系统政策限制,用户无法通过滑动或其他操作调出系统栏。
实现步骤:
首先将你的应用注册为设备所有者:
可以通过ADB命令快速配置(适用于测试设备):dpm set-device-owner com.your.package/.YourDeviceAdminReceiver(需要先创建继承自
DeviceAdminReceiver的广播接收器,并在Manifest中配置相应权限)调用
DevicePolicyManager设置禁用规则:DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName adminComponent = new ComponentName(this, YourDeviceAdminReceiver.class); // 禁用状态栏 dpm.addUserRestriction(adminComponent, UserManager.DISALLOW_STATUS_BAR); // 禁用导航栏 dpm.addUserRestriction(adminComponent, UserManager.DISALLOW_NAVIGATION_BAR);
注意:这种方式需要设备的系统级权限,仅适用于企业设备、定制ROM设备或用户明确授权的场景。
2. 基于WindowInsetsController的沉浸式优化(API 30+适配)
你之前使用的SYSTEM_UI_FLAG系列常量在Android 11(API 30)已被弃用,官方推荐使用WindowInsetsController来控制系统栏显示。虽然无法完全阻止滑动调出,但可以做到调出后自动快速隐藏,且限制操作:
@Override protected void onResume() { super.onResume(); Window window = getWindow(); WindowInsetsController controller = window.getInsetsController(); if (controller != null) { // 隐藏状态栏和导航栏 controller.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); // 设置系统栏行为:禁止通过滑动触发显示(部分设备需测试适配) controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_NEVER_HIDE); } // 设置窗口全屏布局,避免系统栏弹出时挤压界面 window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } // 监听窗口焦点,重新获取焦点时立刻隐藏系统栏 @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { Window window = getWindow(); WindowInsetsController controller = window.getInsetsController(); if (controller != null) { controller.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); } } }
3. 拦截边缘触摸事件(极端场景补充)
如果以上方法仍无法满足需求,可以尝试在Activity中拦截系统栏触发区域的触摸事件,阻止用户调出系统栏:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int screenHeight = getResources().getDisplayMetrics().heightPixels; // 定义触发系统栏的边缘区域(可根据设备调整像素值) int edgeSize = 100; // 拦截顶部状态栏触发区域的触摸 if (ev.getY() <= edgeSize) { return true; } // 拦截底部导航栏触发区域的触摸 if (ev.getY() >= screenHeight - edgeSize) { return true; } // 部分设备支持左右边缘调出导航栏,可根据需要添加拦截逻辑 return super.dispatchTouchEvent(ev); }
注意:这种方法可能会影响正常的界面触摸操作,需要根据你的应用场景调整边缘区域的大小。
内容的提问来源于stack exchange,提问作者MOMO
相关产品推荐
相关产品推荐

