Android:如何获取沉浸式导航栏的显示与隐藏状态?
Android 沉浸式导航栏状态监听方案
官方原生回调(API 30+ 适用)
Android 11(API 级别 30)开始,SDK 正式提供了 WindowInsetsAnimation.Callback 接口,支持监听系统栏(包含底部导航栏、顶部状态栏)的显隐动画全流程,可直接获取对应的状态变更时机:
- 通过
Window#setWindowInsetsAnimationCallback()方法注册回调 - 回调的
onStart()方法会在导航栏显隐动画启动时触发,对应状态变化的开始时机 - 回调的
onEnd()方法会在导航栏显隐动画结束时触发,对应状态变化的完成时机
示例代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.setWindowInsetsAnimationCallback(object : WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { override fun onStart( animation: WindowInsetsAnimation, bounds: WindowInsetsAnimation.Bounds ): WindowInsetsAnimation.Bounds { // 导航栏显隐动画启动,可获取目标状态 val willNavShow = animation.typeMask and WindowInsets.Type.navigationBars() != 0 // 你的业务逻辑 return super.onStart(animation, bounds) } override fun onEnd(animation: WindowInsetsAnimation) { super.onEnd(animation) // 导航栏显隐动画结束,最终状态确认 val isNavVisible = window.decorView.rootWindowInsets.isVisible(WindowInsets.Type.navigationBars()) // 你的业务逻辑 } }) }
低版本兼容方案(API <30 适用)
低于 Android 11 的版本没有提供专用的导航栏状态回调,可通过监听布局变化间接判断显隐时机:
- 给 Activity 根布局注册
View.OnLayoutChangeListener监听 - 每次布局变更时计算导航栏高度,对比前后值即可判断显隐状态是否发生变化
示例代码:
private int lastNavHeight = 0; // rootView 为 Activity 根布局 rootView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { Rect visibleRect = new Rect(); getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleRect); int screenHeight = getResources().getDisplayMetrics().heightPixels; int currentNavHeight = screenHeight - visibleRect.bottom; if (currentNavHeight != lastNavHeight) { // 导航栏状态变更:currentNavHeight > 0 为显示,等于0为隐藏 lastNavHeight = currentNavHeight; // 你的业务逻辑 } });
适配注意点
- 部分厂商定制ROM修改了系统栏的显示逻辑,少数场景下需要额外适配
- 回调中不要执行耗时操作,避免阻塞界面动画渲染
内容的提问来源于stack exchange,提问作者ByMedion
相关产品推荐
相关产品推荐

