Nav Graph绑定Bottom Nav View时可否混合使用普通Fragment管理器?
这个需求完全可以实现,不需要为全部5个标签页都配置导航图,最优实现方案如下:
核心原理
Android 官方的NavigationUI.setupWithNavController是封装好的便捷绑定方法,本身没有强制要求所有菜单项都必须走Nav Graph逻辑。你完全可以通过自定义点击事件拦截,拆分两类标签页的跳转逻辑。
具体实现步骤
- 首先仅在Nav Graph中保留需要沿用导航逻辑的3个Fragment对应的目的地配置,剩下2个不需要加入导航图
- 不要使用默认的
NavigationUI.setupWithNavController一键绑定方法,改为自定义点击处理逻辑 - 给BottomNavigationView设置自定义选中监听,示例代码如下:
bottomNavigationView.setOnItemSelectedListener { menuItem -> when (menuItem.itemId) { // 匹配走Nav Graph逻辑的3个标签ID,和导航图目的地ID保持一致即可 R.id.tab_home, R.id.tab_square, R.id.tab_message -> { navController.navigate(menuItem.itemId) true } // 匹配走普通FragmentManager管理的2个标签ID R.id.tab_tool, R.id.tab_mine -> { val targetFragment = when(menuItem.itemId) { R.id.tab_tool -> ToolFragment() R.id.tab_mine -> MineFragment() else -> return@setOnItemSelectedListener false } supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, targetFragment) // 按需添加addToBackStack、自定义切换动画等配置 .commit() true } else -> false } }
- 补充回退栈适配逻辑,如果需要点击返回键优先处理普通Fragment的回退,再处理Nav Graph的回退,重写Activity的
onBackPressed方法:
override fun onBackPressed() { if (supportFragmentManager.backStackEntryCount > 0) { supportFragmentManager.popBackStack() } else if (navController.previousBackStackEntry != null) { navController.popBackStack() } else { super.onBackPressed() } }
额外优化建议
- 两类Fragment建议共用同一个布局容器,避免出现UI层级重叠、切换闪烁的问题
- 如果需要保留标签页切换时的Fragment状态,普通Fragment切换可以用
show/hide方法代替replace,减少页面重绘损耗 - 不需要走Nav Graph的标签不要在导航图中注册,避免出现多余的无效目的地配置
内容的提问来源于stack exchange,提问作者Farooq Arshed
相关产品推荐
相关产品推荐

