防止导航到相同的片段

13
我正在使用带有 BottomNavigationView 的 Android 导航 Jetpack 库。我已经实现了 NavHost、NavGraph 和我的片段。当我使用操作进行导航时,一切都按预期工作。
我使用以下代码来设置所有内容:
 val navController = Navigation.findNavController(this, R.id.nav_host)
 bottom_navigation.setupWithNavController(navController)

问题在于,如果我点击一个选项卡两次,片段就会被创建两次。有没有办法拦截导航?我不想导航到已经显示的相同片段。

4个回答

39

根据此问题

可以自由设置OnNavigationItemReselectedListener,它优先于NavigationUI设置的OnNavigationItemSelectedListener

val navController = Navigation.findNavController(this, R.id.nav_host)
bottom_navigation.setupWithNavController(navController)
bottom_navigation.setOnNavigationItemReselectedListener {
  // Do nothing to ignore the reselection
}

1
谢谢。看起来这修复了重建的问题。但是,如果我从选定的标签内的片段A导航到B,再次点击该标签应该将其导航到片段A,但它没有。我可以设置一个NavigationItemSelectedListener并进行一些检查,但这会破坏bottom_navigation.setupWithNavController(navController)的目的。我错过了什么吗? - Nacho Ramos Sánchez
1
如果您在重新选择时有自定义逻辑(例如调用 navController.popBackStack(it.itemId, false) 返回该选项卡的第一个屏幕),那么您应该将该逻辑放在重新选择侦听器中,而不是什么都不做。 - ianhanniballake
非常感谢这个。我甚至不知道BottomNavigationView上有监听器可用。 - dave o grady
非常感谢,我花了很多时间搜索这些关键字。 - Aldan
1
抱歉,对我来说这没起作用。我遇到了提到的问题,但是使用 setOnNavigationItemReselectedListener{ navController.popBackStack(it.itemId, false) } 后,在从 A 导航到 B 并通过按底部选项卡返回到 A 时,片段会被重新创建。因为在这种情况下 setOnNavigationItemReselectedListener 没有被触发。你们能帮我吗? - JonasPTFL

4

setOnItemSelectedListener内使用:

if( item.getItemId() == navController.getCurrentDestination().getId()){  return true; }

因为 OnNavigationItemSelectedListener 现在已经过时了。


0

我遇到了同样的问题,在使用 About 页面(使用非常好的 AboutLibraries 库)时,它会堆叠重复的页面。最终我在 OnOptionsItemSelected 方法中处理了这个问题。

            case R.id.action_about:
            NavController navController = Navigation.findNavController( this, R.id.nav_host_fragment );
            if ( navController.getCurrentDestination().getId() != R.id.nav_about )
            {
                navController.navigate( R.id.nav_about );
            }

现在它只显示一个片段,而不会将相同的片段叠加在其上。很遗憾这种行为不能在XML中定义,我需要在代码中实现。


0
我写了这个扩展。它将检查当前片段与目标是否相同,如果是,则仅关闭抽屉。但在关闭抽屉时存在一些动画问题。
fun NavigationView.setupWithUniqueFragment(navController: NavController) {

    this.setNavigationItemSelectedListener(object : NavigationView.OnNavigationItemSelectedListener {
        override fun onNavigationItemSelected(item: MenuItem): Boolean {
            val parent = this@setupWithUniqueFragment.parent
            if (item.itemId == navController.currentDestination?.id) {
                if (parent is DrawerLayout) {
                    parent.closeDrawer(this@setupWithUniqueFragment, true)
                }
                return true
            }
            val handled = NavigationUI.onNavDestinationSelected(item, navController)
            if (handled) {
                if (parent is DrawerLayout) {
                    parent.closeDrawer(this@setupWithUniqueFragment, true)
                }
            }
            return handled
        }

    })

    val weakReference = WeakReference<NavigationView>(this@setupWithUniqueFragment)
    navController.addOnDestinationChangedListener(
        object : NavController.OnDestinationChangedListener {
            override fun onDestinationChanged(
                controller: NavController,
                destination: NavDestination, arguments: Bundle?
            ) {
                val view = weakReference.get()
                if (view == null) {
                    navController.removeOnDestinationChangedListener(this)
                    return
                }
                val menu = view.menu
                var h = 0
                val size = menu.size()
                while (h < size) {
                    val item = menu.getItem(h)
                    item.isChecked = matchDestination(destination, item.itemId)
                    h++
                }
            }
        })
}

internal fun matchDestination(
    destination: NavDestination,
    @IdRes destId: Int
): Boolean {
    var currentDestination: NavDestination? = destination
    while (currentDestination!!.id != destId && currentDestination.parent != null) {
        currentDestination = currentDestination.parent
    }
    return currentDestination.id == destId
}

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