使用具有多个导航图和类似于Google导航示例的BottomNavigationView的导航组件时,我遇到了这样的问题。
我无法以编程方式从底部导航中的一个选项卡导航到另一个选项卡并传递参数。例如,我有三个导航图和三个底部导航选项卡(每个选项卡一个图)。
我需要以编程方式从一个选项卡导航到另一个选项卡,以便“另一个”选项卡可以获得来自第一个选项卡的传递参数。
使用具有多个导航图和类似于Google导航示例的BottomNavigationView的导航组件时,我遇到了这样的问题。
我无法以编程方式从底部导航中的一个选项卡导航到另一个选项卡并传递参数。例如,我有三个导航图和三个底部导航选项卡(每个选项卡一个图)。
我需要以编程方式从一个选项卡导航到另一个选项卡,以便“另一个”选项卡可以获得来自第一个选项卡的传递参数。
如果您需要将大量数据从一个选项卡移动到另一个选项卡,那么您可能需要一个本地数据库。此外,您可以使用Intents传递它们。但是,如果您不知道如何实现底部导航栏或选项卡,则建议您查看以下内容:
https://medium.com/@suragch/how-to-add-a-bottom-navigation-bar-in-android-958ed728ef6c
https://androidwave.com/bottom-navigation-bar-android-example/
https://medium.com/@droidbyme/android-material-design-tabs-tab-layout-with-swipe-884085ae80ff
我成功地创建了一个解决方法,基于androidx.navigation.ui.NavigationUI
的内部实现。
引入以下接口:
/**
* Use this interface to navigate between bottom tabs instead of findNavController().navigate().
*
* Using navController's navigation can lead to incorrect app states, because each tab
* holds its own backstack. If for example you want to open tab2 from tab1
* by clicking button on tab1 fragment, tab2 fragment will be added to tab1 backstack.
* In the same time tab2 will get highlighted, so clicking on tab1 to navigate back to tab1 backstack
* will have no action, since you are already on tab1.
*
*/
interface BottomTabNavigator {
fun openTab(@IdRes tabId: Int, args: Bundle? = null)
}
在设置导航栏的位置(通常是MainActivity
)提供以下实现:
override fun openTab(@IdRes tabId: Int, args: Bundle?) {
val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController // obtain nav controller. This code may differ depending on the place in which you are implementing this interface
val menuItem = binding.bottomNav.menu.findItem(tabId) // find menu item associated with tabId, this can also slightly differ depending on how you access bottomNav
openTab(
menuItem = menuItem,
navController = navController,
args = args,
restoreState = restoreState
)
}
/**
* Implementation is based on [NavigationUI.onNavDestinationSelected].
* It works similarly, but additionally allows for passing args.
*/
private fun openTab(menuItem: MenuItem, navController: NavController, args: Bundle?, restoreState: Boolean): Boolean {
val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true) // you can also add restoreState to openTab in BottomTabNavigator if you need to set it from outside
if (menuItem.order and Menu.CATEGORY_SECONDARY == 0) {
builder.setPopUpTo(
destinationId = navController.graph.findStartDestination().id,
inclusive = false,
saveState = true
)
}
return try {
navController.navigate(
resId = menuItem.itemId,
args = args,
navOptions = builder.build()
)
navController.currentDestination?.matchDestination(item.itemId) == true
} catch (e: IllegalArgumentException) {
false
}
}
// matchDestination is internal in NavigationUI.onNavDestinationSelected, we have to port it as well.
fun NavDestination.matchDestination(@IdRes destId: Int): Boolean =
hierarchy.any { it.id == destId }
你可以在Fragment中使用它,例如:
val bottomTabNavigator = requireActivity() as BottomTabNavigator
bottomTabNavigator.openTab(R.id.myTabId, bundleOf("myKey", "myValue")
navController.navigate()
,但是当我尝试导航到与我的选项卡相关联的目标时(如docs中所述),会出现问题。从选项卡1导航到选项卡2可以正常工作,但是当按下选项卡1以返回它时,仍然停留在选项卡2上。Title.kt
中替换view.findViewById<Button>(R.id.about_btn).setOnClickListener {
findNavController().navigate(R.id.action_title_to_about)
}
使用
view.findViewById<Button>(R.id.about_btn).setOnClickListener {
findNavController().navigate(
resId = R.id.list,
args = null, // note that I don't pass args here, but it is to show case different issue
navOptions = NavOptions.Builder().setPopUpTo(R.id.list, false).build()
)
}
运行应用程序并执行以下操作: