【问题标题】:Prevent navigating to the same fragment防止导航到同一个片段
【发布时间】:2020-02-01 06:16:35
【问题描述】:

我正在使用带有 BottomNavigationView 的 Android 导航喷气背包库。我已经实现了 NavHost、NavGraph 和我的片段。当我使用操作进行导航时,一切都按预期工作。

我使用以下代码来设置所有内容:

 val navController = Navigation.findNavController(this, R.id.nav_host)
 bottom_navigation.setupWithNavController(navController)

问题是,如果我单击一个选项卡 2 次,片段会重新创建两次。有没有办法拦截导航?我不想导航到正在显示的同一片段。

【问题讨论】:

    标签: android kotlin android-jetpack android-jetpack-navigation


    【解决方案1】:

    根据this issue

    随意设置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
    }
    

    【讨论】:

    • 谢谢。这似乎解决了娱乐问题。但是,如果我在同一个选定选项卡内从片段 A 导航到 B,再次单击此选项卡应该导航到片段 A,但它没有。我可以设置一个 NavigationItemSelectedListener 并进行一些检查,但这会搞砸bottom_navigation.setupWithNavController(navController) purpose。我错过了什么?
    • 如果您在重新选择时想要执行自定义逻辑(例如调用 navController.popBackStack(it.itemId, false) 返回该选项卡的第一个屏幕),那么您希望将该逻辑放入重新选择中倾听者而不是什么都不做。
    • 非常感谢。我什至不知道 BottomNavigationView 有可用的侦听器。
    • 坦克这么多,我花了时间搜索这些关键字
    • 对不起,但对我来说这没有用。我面临着上述问题,但使用setOnNavigationItemReselectedListener{ navController.popBackStack(it.itemId, false) },当通过按底部选项卡导航回A 时,从A 导航到B 后会重新创建片段。因为在这种情况下不会触发 setOnNavigationItemReselectedListener 。请大家帮帮我好吗?
    【解决方案2】:

    setOnItemSelectedListener里面使用:

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

    因为 OnNavigationItemSelectedListener 现在已被弃用。

    【讨论】:

      【解决方案3】:

      我写了这个扩展。它将检查当前片段和目的地,如果两者相同,它只会关闭抽屉。但是关闭抽屉时存在一些动画问题。

      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
      }
      

      【讨论】:

        【解决方案4】:

        我在使用 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 中定义,我需要在代码中执行此操作。

        【讨论】:

          猜你喜欢
          • 2020-09-03
          • 1970-01-01
          • 1970-01-01
          • 2013-05-12
          • 2019-06-14
          • 2013-12-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多