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

5

我希望大部分菜单项由Navigation组件的控制器处理,但我也想像这样单独处理一个“退出登录”菜单项:

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)

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

我会将此项从您的导航菜单中删除,并改为页脚/按钮。 - martinseal1987
2个回答

6
我不确定目前是否有正确的方法来解决这个问题,但您可以选择不使用setupWithNavController方法。
我也遇到了这个问题,并将我的调用setNavigationItemSelectedListener的代码移动到之后调用setupWithNavController,此时退出登录的导航代码是可以运行的,但其他导航却不能运行。我认为这意味着当再次调用setNavigationItemSelectedListener时,navigationListener会被覆盖,并且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
    }

0

类似于Justin的回答,我从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(),以便您可以使用某个公共 setter 传递的自己的监听器调用包含实际监听器的包装器,该监听器由 NavigationUI 设置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接