如何在Navigation UI中监听导航栏返回箭头点击并执行自定义操作
前置说明
你需要已经在宿主Activity中完成Toolbar与NavController的绑定:NavigationUI.setupWithNavController(toolbar, navController),以下两种方案可以根据你的业务场景选择。
方案1:仅拦截Toolbar返回箭头点击
适用于只需要监听Toolbar返回按钮,不需要处理系统物理/手势返回键的场景
- 如果你的项目AppCompat版本低于1.4.0,重写Fragment的
onOptionsItemSelected方法即可:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 开启Fragment的菜单接收权限 setHasOptionsMenu(true) } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { // 执行你的自定义逻辑,比如校验表单、弹保存提示等 val isAllowBack = checkFormStatus() return if (isAllowBack) { // 返回false/调用super都可以,走默认Navigation返回逻辑 super.onOptionsItemSelected(item) } else { // 消费事件,拦截返回 true } } return super.onOptionsItemSelected(item) }
- 如果你的项目使用AppCompat 1.4.0及以上版本,
setHasOptionsMenu已废弃,推荐使用MenuProvider实现:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 绑定生命周期自动回收,不需要手动反注册 requireActivity().addMenuProvider(object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {} override fun onMenuItemSelected(menuItem: MenuItem): Boolean { if (menuItem.itemId == android.R.id.home) { val isAllowBack = checkFormStatus() return if (!isAllowBack) { // 执行自定义拦截逻辑 showUnsavedDataAlert() // 返回true表示消费事件,停止后续传递 true } else { // 返回false表示不消费,走默认返回逻辑 false } } return false } }, viewLifecycleOwner, Lifecycle.State.RESUMED) }
方案2:同时拦截Toolbar返回和系统返回键
适用于需要统一两种返回行为的场景,不需要写两套拦截逻辑
- 首先在宿主Activity中替换Toolbar的默认导航点击逻辑:
// 替代默认的NavigationUI绑定的导航点击事件 toolbar.setNavigationOnClickListener { // 先触发回退栈逻辑,如果没有自定义回调消费,会自动执行默认返回 if (!navController.popBackStack()) { // 如果已经是根Fragment,关闭Activity finish() } }
- 在需要拦截的Fragment中注册OnBackPressedCallback:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val customBackCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { val isAllowBack = checkCustomBusiness() if (isAllowBack) { // 允许返回,关闭当前回调后执行默认返回逻辑 isEnabled = false requireActivity().onBackPressedDispatcher.onBackPressed() } // 不允许返回的情况下不需要做任何操作,自动拦截 } } // 绑定Fragment生命周期,销毁时自动回收 requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, customBackCallback) }
两种方案都不需要修改Activity的原有逻辑,只会在指定Fragment生效,退出Fragment后自动恢复默认返回行为。
内容的提问来源于stack exchange,提问作者Ziyaad Shiraz
相关产品推荐
相关产品推荐

