android 使用bottomnavigation和navigation-component在选项卡之间传递数据

rmbxnbpk  于 2023-04-10  发布在  Android
关注(0)|答案(2)|浏览(112)

使用带有多个导航图的Navigation组件和类似于google navigation sample的BottomNavigationView,我遇到了这样的问题。
我不能通过传递参数从底部导航的一个标签页导航到另一个标签页。例如,我有三个导航图和底部导航的三个标签页(每个标签页一个图)。
我需要以编程方式从一个选项卡导航到另一个,使“另一个”选项卡获取参数从第一个选项卡传递。

ttcibm8c

ttcibm8c1#

你可能需要一个本地数据库,如果你有很多数据要从一个标签移动到other.as,你可以用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

q3qa4bjr

q3qa4bjr2#

我设法创建了一个基于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)
}

在设置navBar的地方提供以下实现(通常为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 }

你可以在以后的片段中使用它,比如:

val bottomTabNavigator = requireActivity() as BottomTabNavigator
bottomTabNavigator.openTab(R.id.myTabId, bundleOf("myKey", "myValue")

我真的希望我们可以只使用navController.navigate(),但当我试图导航到与我的标签绑定的目的地时(如文档中所提到的)。从tab1导航到tab2工作,但然后按tab1返回它停留在tab2上。
你甚至可以在nav sample中看到它:
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()
    )
}

运行应用程序并:

  • 应用程序在“主页”选项卡上打开
  • 单击“关于”按钮
  • 它会将您带到排行榜选项卡
  • 单击“主页”选项卡
  • 它将突出显示“主页”选项卡,但您将停留在“排行榜”片段

相关问题