为什么Navigation Drawer的MenuItem点击不触发OnNavigationItemSelectedListener回调?
问题原因
- 你调用
NavigationUI.setupWithNavController(navigationView, navController)的时机在navigationView.setNavigationItemSelectedListener(this)之后,setupWithNavController方法内部会自动为NavigationView设置一个默认的选中监听器,直接覆盖了你之前设置的自定义监听器,所以你的onNavigationItemSelected不会被触发。 - 系统默认监听器会自动匹配menu的itemId和导航图中声明的destinationId,所以会自动切换Fragment,这就是你看到Fragment自动切换但自定义回调不执行的原因。
解决方案
方案1:调整设置顺序,保留Navigation组件的自动能力
如果你需要同时用到Navigation组件的自动页面切换、顶部栏联动等能力,还要加自定义逻辑,就调整代码顺序:
- 先执行
NavigationUI.setupWithNavController - 再设置你自定义的
OnNavigationItemSelectedListener - 在你的回调方法中,先调用
NavigationUI.onNavDestinationSelected()处理默认导航逻辑,再写自己的自定义逻辑。
修改后的onCreate对应部分代码:
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); // 先调用setupWithNavController NavigationUI.setupWithNavController(navigationView, navController); // 再设置自定义监听器 navigationView.setNavigationItemSelectedListener(this);
修改后的onNavigationItemSelected回调代码:
@Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { // 先让Navigation组件处理默认的导航逻辑 NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); boolean handled = NavigationUI.onNavDestinationSelected(menuItem, navController); if (handled) { // 这里加你自己的自定义逻辑,比如传参、埋点、修改标题等 System.out.println("clicked"); switch (menuItem.getItemId()) { case R.id.nav_home: Bundle args = new Bundle(); args.putString("url", "MyText"); // 不要自己创建Fragment实例,Navigation组件会自动创建,传参直接通过目的地设置 navController.getCurrentDestination().addArgument("url", NavType.StringType, false, "MyText"); break; case R.id.nav_gallery: Bundle args1 = new Bundle(); args1.putString("url", "My Text2"); navController.getCurrentDestination().addArgument("url", NavType.StringType, false, "My Text2"); break; } DrawerLayout drawer = binding.drawerLayout; drawer.closeDrawer(GravityCompat.START); } return handled; }
方案2:完全自定义导航逻辑,移除默认处理
如果你不需要Navigation组件自动处理页面切换,直接删除NavigationUI.setupWithNavController(navigationView, navController)这行代码即可,你的自定义监听器就会正常生效。
额外注意事项
- 你原有代码中
R.id.nav_home的分支没有初始化fragment就调用fragment.setArguments(args),会直接触发空指针异常,需要修正。 - 如果你使用Navigation组件,不要自己用
FragmentManager做replace操作,会和Navigation的回退栈、生命周期管理冲突,统一用NavController处理导航。
内容的提问来源于stack exchange,提问作者Jhon Jesus
相关产品推荐
相关产品推荐

