防止导航到同一个片段
Prevent navigating to the same fragment
我将 Android 导航喷气背包库与 BottomNavigationView 一起使用。我已经实现了 NavHost、NavGraph 和我的片段。当我使用操作进行导航时,一切都按预期工作。
我使用以下代码设置所有内容:
val navController = Navigation.findNavController(this, R.id.nav_host)
bottom_navigation.setupWithNavController(navController)
问题是,如果我点击某个选项卡 2 次,片段会重新创建两次。有什么办法可以拦截导航吗?我不想导航到正在显示的同一片段。
根据this issue,
Feel free to set a OnNavigationItemReselectedListener, which takes precedence over the OnNavigationItemSelectedListener
set by NavigationUI.
val navController = Navigation.findNavController(this, R.id.nav_host)
bottom_navigation.setupWithNavController(navController)
bottom_navigation.setOnNavigationItemReselectedListener {
// Do nothing to ignore the reselection
}
我写这个扩展。它将检查当前片段和目的地,如果两者相同,它只会关闭抽屉。但是关闭抽屉时存在一些动画问题。
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
}
我在使用关于页面(使用非常好的 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 中定义,我需要在代码中进行定义。
在 setOnItemSelectedListener 中使用 :
if( item.getItemId() == navController.getCurrentDestination().getId()){ return true; }
因为 OnNavigationItemSelectedListener 现在已弃用。
我将 Android 导航喷气背包库与 BottomNavigationView 一起使用。我已经实现了 NavHost、NavGraph 和我的片段。当我使用操作进行导航时,一切都按预期工作。
我使用以下代码设置所有内容:
val navController = Navigation.findNavController(this, R.id.nav_host)
bottom_navigation.setupWithNavController(navController)
问题是,如果我点击某个选项卡 2 次,片段会重新创建两次。有什么办法可以拦截导航吗?我不想导航到正在显示的同一片段。
根据this issue,
Feel free to set a OnNavigationItemReselectedListener, which takes precedence over the
OnNavigationItemSelectedListener
set by NavigationUI.
val navController = Navigation.findNavController(this, R.id.nav_host)
bottom_navigation.setupWithNavController(navController)
bottom_navigation.setOnNavigationItemReselectedListener {
// Do nothing to ignore the reselection
}
我写这个扩展。它将检查当前片段和目的地,如果两者相同,它只会关闭抽屉。但是关闭抽屉时存在一些动画问题。
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
}
我在使用关于页面(使用非常好的 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 中定义,我需要在代码中进行定义。
在 setOnItemSelectedListener 中使用 :
if( item.getItemId() == navController.getCurrentDestination().getId()){ return true; }
因为 OnNavigationItemSelectedListener 现在已弃用。