如何使用导航控制器设置导航抽屉并处理单个菜单项



我希望大部分菜单项由导航组件的控制器处理,但我也想像这样单独处理一个"注销"菜单项:

val navController = findNavController(R.id.nav_host_fragment)
        nav_view.setNavigationItemSelectedListener { item ->
            when(item.itemId) {
                R.id.logout_menu_item -> {
                    Toast.makeText(context, "Logut Menu Item Touched", Toast.LENGTH_LONG).show()
                    true
                }
                else -> false
            }
        }
        nav_view.setupWithNavController(navController)
        bottom_navigation.setupWithNavController(navController)

为什么这不起作用,以及如何解决此问题?

我不确定目前是否有适当的方法来执行此操作,但您始终可以不使用setupWithNavController方法。

我也遇到了这个问题,作为测试,在调用setupWithNavController之后将我的呼叫移动到setNavigationItemSelectedListener,并且我用于注销的导航代码正在运行,但导航的其余部分没有。我认为这意味着导航侦听器在后续调用setNavigationItemSelectedListener时被覆盖,并且setupWithNavController调用setNavigationItemSelectedListener内部。

我试图在谷歌源代码中验证这一点,但无法轻松找到存储库。

我通过不调用setupWithNavController而是执行以下操作来解决此问题:

    navigationDrawer?.setNavigationItemSelectedListener { menuItem ->
        if (menuItem.itemId == R.id.action_sign_out) {
            // sign out logic
            return@setNavigationItemSelectedListener true
        }
        val result = menuItem.onNavDestinationSelected(navigationController)
        drawerLayout?.closeDrawers()
        result
    }

与贾斯汀的回答类似,我从 NavigationUI 复制了侦听器设置代码,如下所示:

fun NavigationView.setupWithNavController(navController: NavController, onMenuItemSelected: (MenuItem) -> Boolean) {
    NavigationUI.setupWithNavController(this, navController) // because this does more than set the nav view listener
    setNavigationItemSelectedListener { item ->
        if (onMenuItemSelected(item)) {
            return@setNavigationItemSelectedListener true
        }
        NavigationUI.onNavDestinationSelected(item, navController).also {
            val parent = parent
            if (parent is DrawerLayout) {
                parent.closeDrawer(this)
            } else {
                findBottomSheetBehavior()?.state = BottomSheetBehavior.STATE_HIDDEN
            }
        }
    }
}
private fun View.findBottomSheetBehavior(): BottomSheetBehavior<*>? {
    val params = layoutParams
    if (params !is CoordinatorLayout.LayoutParams) {
        return (parent as? View)?.findBottomSheetBehavior()
    }
    return params.behavior as? BottomSheetBehavior<*>
}

然后,在Activity.onCreate()

navigation_view.setupWithNavController(navController) { item ->
    when (item.itemId) {
        R.id.mySpecialFragment ->
            // do something special like: navController.popBackStack(id, true)
    }
    false // usually still want to perform default steps
}

一个更防弹的解决方案可能涉及子类化NavigationView和覆盖setNavigationItemSelectedListener(),以便您可以将NavigationUI设置的实际侦听器包装为一个包含通过某个公共setter传入的对您自己的侦听器的调用的侦听器。

最新更新