androidx.navigation菜单项的多个目的地

问题描述

我有一个使用androidx导航库的活动应用程序。对于菜单目标之一,我实际上将一个片段作为目标而没有任何视图,根据用户提供的配置,该视图要么重定向到应该存在的实际目标,要么重定向到当前两个不同的视图之一,告诉用户他需要首先设置一个配置,或者当前没有活动的配置(已删除?),并且他需要选择一个可用的配置。

现在,从功能上讲,这种方法可以很好地工作。但是,由于androidx导航按ID将菜单项与目标联系在一起,因此从不选择将您带到该视图的菜单项,因为它与其中没有视图的片段目标相匹配。

我试图将NavController.OnDestinationChangedListener添加到我的活动中,并将其添加到navController navController.addOnDestinationChangedListener(this)中。但是后来似乎被导航覆盖了。

override fun onDestinationChanged(controller: NavController,destination: NavDestination,arguments: Bundle?) {
    val destinations = listof(R.id.destinationA,R.id.destinationB,R.id.destinationC)

    if(destinations.contains(destination.id)) {
        nav_view.menu.getItem(0).isChecked = true
    }
}

绝对是正确的菜单项。当我将isChecked = true更改为isEnabled = false时,无法再单击它。

此外,当我进行这种奇怪的修改时,它也会起作用

GlobalScope.launch(dispatchers.Main) {
    delay(1000)
    nav_view.menu.getItem(0).isChecked = true
}

不用说这不是一个很好的解决方案。


在这方面,任何人都知道如何超越androidx导航的认行为吗?

稍后,我会再回过头来,如果我找到合适的解决方案,请报告。

如果当前无法执行此操作,那么为抽屉打开添加一个侦听器并设置所选菜单项可能是一个不错的解决方法

解决方法

代替documentation中提到的setupWithNavController(),而是自己进行设置。

here所述,当您使用onNavDestinationSelected()设置菜单项时,如果单击菜单项,则会调用NavigationUI中的setupWithNavController()帮助方法。因此,您可以尝试执行以下操作:

yourNavigationView.setNavigationItemSelectedListener { item: MenuItem ->
    if(item.itemId == R.id.noViewFragmentId) {
        val isConfigurationProvided = ...
        if(!isConfigurationProvided) {
            //Perform your actions (navigate to either of the two alternate views)
            return@setNavigationItemSelectedListener true
        }
    }

    val success = NavigationUI.onNavDestinationSelected(item,navController)

    if(success) {
        drawerLayout.closeDrawer(GravityCompat.START)
        item.isChecked = true
    }
            
    success
}
,

我将其添加为可能的解决方案,并暂时坚持使用。我仍然觉得应该有一个更好的方法来执行此操作,因此我不会将其视为遮阳篷。

从本质上讲,这是我在写问题结束时得到的想法

如果当前无法执行此操作,那么为抽屉打开添加一个侦听器并设置所选菜单项可能是一个不错的解决方法。

class SetActiveMenuDrawerListener(
        private val navController: NavController,navigationView: NavigationView) : DrawerLayout.DrawerListener {

    private var checked = false
    private val destinations = listOf(R.id.destinationA,R.id.destinationB,R.id.destinationC)
    private val menu = navigationView.menu.getItem(0)

    init {
        navController.addOnDestinationChangedListener { _,_,_ -> checked = false }
    }

    override fun onDrawerSlide(drawerView: View,slideOffset: Float) {
    }

    override fun onDrawerOpened(drawerView: View) {
    }

    override fun onDrawerClosed(drawerView: View) {
    }

    override fun onDrawerStateChanged(newState: Int) {
        if(checked) return
        val currentDestination = navController.currentDestination ?: return

        if(destinations.contains(currentDestination.id)) {
            menu.isChecked = true
        }
        checked = true
    }
}

然后将其添加到DrawerLayout

drawer_layout.addDrawerListener(SetActiveMenuDrawerListener(navController,nav_view))

我确实将代码添加到了onDrawerStateChanged而不是onDrawerOpened中,因为如果单击抽屉,onDrawerOpened就会被调用得有点晚,而拖动时根本没有。

这不是漂亮的东西,但可以完成工作。