如何在系统栏间绘制内容并保持系统栏完全不透明?
解决方案:让应用接收全屏幕AMotionEvent并适配两种窗口模式
一、非全屏窗口模式:状态栏/导航栏可见且不拦截触摸事件
要实现状态栏、应用窗口、导航栏依次显示,同时让应用接收屏幕所有像素的触摸事件,核心是让应用窗口布局延伸至系统栏下方,同时禁用系统栏的触摸拦截:
- 在Activity的
onCreate方法中配置窗口属性:
Window window = getWindow(); // 让窗口布局覆盖整个屏幕(包括系统栏区域) window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); // 设置状态栏、导航栏为半透明(保持可见,避免遮挡应用内容) window.setStatusBarColor(Color.parseColor("#80000000")); window.setNavigationBarColor(Color.parseColor("#80000000")); // 配置系统UI可见性,确保应用布局延伸至系统栏区域 View decorView = window.getDecorView(); decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION );
- 布局文件中设置根布局属性:
确保根布局的android:fitsSystemWindows="false",避免系统自动调整布局避开系统栏区域。
这样设置后,状态栏和导航栏会显示在应用内容上方,但所有屏幕区域的AMotionEvent都会优先传递给应用,不会被系统栏拦截。
二、全屏窗口模式:应用占满屏幕,边缘拉动唤起系统栏
针对全屏需求,使用沉浸式粘性全屏模式替代普通窗口标记,既实现应用全屏显示,又支持边缘拉动唤起系统栏,同时保证应用接收全屏幕触摸事件:
- 基础全屏配置(兼容Android 10及以下):
View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility( // 粘性沉浸式模式:边缘拉动临时显示系统栏,松手后自动隐藏 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // 隐藏状态栏和导航栏 | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // 让布局延伸至系统栏区域 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION ); // 让窗口覆盖全屏幕 getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); // 设置系统栏透明,视觉上完全全屏 getWindow().setStatusBarColor(Color.TRANSPARENT); getWindow().setNavigationBarColor(Color.TRANSPARENT);
- Android 11+适配:
使用WindowInsetsController替代旧的系统UI可见性配置,兼容性更好:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { WindowInsetsController insetsController = getWindow().getInsetsController(); if (insetsController != null) { // 隐藏状态栏和导航栏 insetsController.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); // 设置系统栏行为:边缘滑动临时显示 insetsController.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); } }
同样需确保根布局android:fitsSystemWindows="false",保证触摸事件能覆盖全屏幕。
关键说明
- 两种模式都通过让应用窗口覆盖全屏幕实现触摸事件的全接收,系统栏仅作为上层绘制元素,不会拦截非系统交互的触摸事件。
- 若需处理系统栏显示/隐藏的回调,可重写
onSystemUiVisibilityChange(Android 10及以下)或监听WindowInsets变化(Android 11+)。
内容的提问来源于stack exchange,提问作者dawnmenu
相关产品推荐
相关产品推荐

