Android切换Fragment后Toolbar汉堡图标二次加载不显示
这是Jetpack Navigation组件配合DrawerLayout、BottomNavigationView使用时的典型配置冲突问题:导航组件会在目的地切换时自动更新Toolbar导航图标状态,如果你只给首页配置了顶级目的地、或者手动实现的ActionBarDrawerToggle逻辑和NavigationUI的默认逻辑冲突,就会出现切换tab后图标被覆写消失的问题。首次启动时图标正常是因为onCreate阶段手动调用的syncState()临时生效,后续导航切换事件触发后,Navigation的默认逻辑会用错误的图标状态覆盖原有配置。
修正AppBarConfiguration顶级目的地配置
把BottomNavigationView绑定的所有根Fragment全部设为顶级目的地,不要只配置首页Fragment。正确初始化代码如下:// 传入所有底部tab对应的根Fragment id,漏传就会出现图标异常 val appBarConfiguration = AppBarConfiguration( setOf( R.id.firstFragment, // 首页tab R.id.secondFragment, // 第二个功能tab R.id.thirdFragment // 第三个功能tab ), binding.drawerLayout // 直接绑定根布局的DrawerLayout实例,不要漏传 )注意:这是该类问题最高发的诱因:如果仅将首页加入顶级目的地集合,切换到其他tab时Navigation会判定当前不是顶级页面,尝试渲染返回箭头,但底部tab切换的目的地不会加入返回栈,最终会出现图标空白消失的问题。
移除冗余的ActionBarDrawerToggle手动配置
如果使用NavigationUI提供的setupActionBarWithNavController方法,不需要手动实例化ActionBarDrawerToggle、不需要手动调用syncState()、不需要手动配置setDisplayHomeAsUpEnabled,上述逻辑NavigationUI内部已经做了封装,冗余的手动配置会和组件默认逻辑抢占图标控制权,导致状态混乱。
正确的MainActivity初始化逻辑只需要保留以下代码:private lateinit var navController: NavController private lateinit var appBarConfiguration: AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化Toolbar val toolbar = findViewById<Toolbar>(R.id.toolbar) setSupportActionBar(toolbar) // 初始化导航控制器 navController = findNavController(R.id.nav_host_fragment) // 初始化AppBar配置,参考上一步的写法传入所有顶级目的地和DrawerLayout appBarConfiguration = AppBarConfiguration( setOf(R.id.firstFragment, R.id.secondFragment, R.id.thirdFragment), findViewById<DrawerLayout>(R.id.drawer_layout) ) // 绑定Toolbar与导航控制器 setupActionBarWithNavController(navController, appBarConfiguration) // 绑定底部导航栏与导航控制器 findViewById<BottomNavigationView>(R.id.bottom_nav).setupWithNavController(navController) // 绑定侧滑菜单与导航控制器 findViewById<NavigationView>(R.id.nav_view).setupWithNavController(navController) } // 仅重写onSupportNavigateUp处理向上导航事件,不要自己重写onOptionsItemSelected处理android.R.id.home逻辑 override fun onSupportNavigateUp(): Boolean { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() }排查Fragment中的冗余Toolbar配置
检查所有Fragment的onViewCreated、onResume生命周期代码,删除所有手动修改ActionBar导航状态的代码,这类代码会直接覆写Activity层的统一配置,导致图标异常:// 以下代码全部移除 // (requireActivity() as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false) // (requireActivity() as AppCompatActivity).supportActionBar?.setHomeAsUpIndicator(R.drawable.custom_icon)自定义ActionBarDrawerToggle场景的兼容处理
如果业务需要自定义ActionBarDrawerToggle(比如实现汉堡图标动画、监听抽屉开合状态做额外逻辑),需要给NavController添加目的地变化监听,每次导航切换完成后手动触发图标同步,避免状态被覆盖:navController.addOnDestinationChangedListener { _, _, _ -> toggle.syncState() }
修复完成后按以下流程验证,全部符合即为修复成功:
- 冷启动进入首页,Toolbar正常显示汉堡图标,点击可正常拉出侧滑抽屉
- 点击底部导航切换到其他两个tab,图标保持汉堡样式,可正常打开侧滑抽屉
- 从任意tab进入二级非顶级页面,汉堡图标自动切换为返回箭头,点击可正常返回上一级
- 从二级页面返回对应tab的根页面,图标自动切回汉堡样式,无消失、错位问题
内容的提问来源于stack exchange,提问作者Mohammad

