使用Navigation Component时DialogFragment弹出后沉浸式模式导航栏无法隐藏
沉浸式模式下DialogFragment显示/点击时导航栏无法保持隐藏的解决办法
我用Kotlin开发了一款Android原生游戏,现在卡着个问题:沉浸式模式下,通过Navigation Component弹出DialogFragment时,导航栏没法一直隐藏。之前试过网上的方案,但只要点一下DialogFragment的区域,导航栏就会重新弹出来,实在搞不定的话可能只能转Unity开发了。
我的Navigation组件配置(game_graph.xml):
... <dialog android:id="@+id/settingsFragment" android:name="nochi.words.ui.SettingsFragment" android:label="fragment_settings" tools:layout="@layout/fragment_settings" > </dialog> ...
亲测有效的解决步骤
核心就是让DialogFragment的窗口也强制应用沉浸式规则,同时拦截触摸事件避免系统触发导航栏。
1. 给DialogFragment的窗口设置沉浸式参数
在SettingsFragment里重写onStart(),直接给Dialog的窗口配置:
override fun onStart() { super.onStart() dialog?.window?.let { window -> // 开启粘性沉浸式,隐藏状态栏和导航栏 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) // 让窗口占满整个屏幕,忽略系统栏区域 window.setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ) } }
2. 拦截触摸事件,防止触发导航栏
如果点击Dialog还是会唤起导航栏,就在onViewCreated()里给根布局加触摸监听,每次触摸时重新应用沉浸式:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.rootView.setOnTouchListener { _, event -> if (event.action == MotionEvent.ACTION_DOWN) { // 触摸时重新设置沉浸式,避免系统弹出导航栏 dialog?.window?.decorView?.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN) } false // 返回false保证子控件能正常响应触摸 } }
3. 确保宿主Activity的沉浸式状态稳定
在Activity的onResume()里也重新应用沉浸式,避免Dialog关闭后导航栏异常显示:
override fun onResume() { super.onResume() window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN) }
适配Android 11+的写法
如果你的游戏适配Android 11及以上,建议用新的WindowInsetsController替代旧的systemUiVisibility,兼容性更好:
// 在SettingsFragment的onStart()里替换成这段 dialog?.window?.let { window -> val insetsController = window.insetsController ?: return@let // 隐藏状态栏和导航栏 insetsController.hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) // 设置为滑动时临时显示导航栏,松手后自动隐藏 insetsController.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE }
内容的提问来源于stack exchange,提问作者stack99
相关产品推荐
相关产品推荐

