如何在 Android 中使用带有第二个导航图的动态加载模块执行底部导航



我试图将导航组件与动态功能模块一起使用,用于我当前正在运行的应用程序。最近,我配置了主导航图,用于加载欢迎屏幕和主屏幕之间的导航。

在主屏幕(如主导航图中定义(呈现时,动态功能模块中的片段将

动态加载并使用 BottomNavigationView 显示在布局中,但作为包含的导航图,所包含的导航图中的目标/操作不会在 HomeFragment 的 NavController 中执行或识别。

我的问题是: 如何在主屏幕中成功加载动态功能模块导航图,以确保安装时应用程序中包含的模块的导航流程?

当说"确保所包含模块的导航流"时,我指的是这样一个事实,即包含的导航图及其目标必须与使用单个导航图时与正常导航设置的工作方式相同。

例如,我在主屏幕底部导航中选择了 Tab01,当显示时,会出现一个包含新闻提要信息的列表,然后在新闻项中单击,它会导航到新闻内容片段屏幕。

在这种情况下,将显示此错误:

java.lang.IllegalArgumentException: navigation destination action_news_list_to_detail is unknown to this NavController
at androidx.navigation.NavController.navigate(NavController.java:919)
at androidx.navigation.NavController.navigate(NavController.java:859)
at androidx.navigation.NavController.navigate(NavController.java:845)
at androidx.navigation.NavController.navigate(NavController.java:1093)
at org.example.dfm01.Tab01Fragment.handleSelectedItem(Tab01Fragment.kt:72)
at org.example.dfm01.Tab01Fragment.access$handleSelectedDestination(Tab01Fragment.kt:23)
at org.example.dfm01.Tab01Fragment$setupRecyclerView$$inlined$apply$lambda$1.invoke(Tab01Fragment.kt:58)
at org.example.dfm01.Tab01Fragment$setupRecyclerView$$inlined$apply$lambda$1.invoke(Tab01Fragment.kt:23)
at org.example.dfm01.Tab01recyclerAdapter$ViewHolder$bind$$inlined$apply$lambda$1.onClick(Tab01recyclerAdapter.kt:97)
at android.view.View.performClick(View.java:7155)
at android.view.View.performClickInternal(View.java:7124)
at android.view.View.access$3500(View.java:808)
at android.view.View$PerformClick.run(View.java:27370)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:359)
at android.app.ActivityThread.main(ActivityThread.java:7418)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

我使用以下依赖项进行导航:

api "androidx.navigation:navigation-fragment-ktx:$nav_version"
api "androidx.navigation:navigation-ui-ktx:$nav_version"
api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

代码注释主屏幕/片段

  1. 添加了第二个导航图,该图使用<include-dynamic... />标记加载动态功能模块。

[nav_graph_home.xml]

<?xml version="1.0" encoding="UTF-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include-dynamic
android:id="@+id/included_nav_01"
app:graphPackage="org.example.dfm01"
app:graphResName="nav_tab_01"
app:moduleName="example_dfm_01" />
<include-dynamic
android:id="@+id/included_nav_02"
app:graphPackage="org.example.dfm02"
app:graphResName="nav_tab_02"
app:moduleName="example_dfm_02" />
<include-dynamic
android:id="@+id/included_nav_03"
app:graphPackage="org.example.dfm03"
app:graphResName="nav_tab_03"
app:moduleName="example_dfm_03" />
<include-dynamic
android:id="@+id/included_nav_04"
app:graphPackage="org.example.dfm04"
app:graphResName="nav_tab_04"
app:moduleName="example_dfm_04" />
</navigation>
  1. 主页片段的布局中为底部导航视图小部件配置了一个菜单 xml 文件,后来,在布局中,我在 FragmentContainerView 中添加了 app:menu 和图形引用。

[fragment_home.xml]

<?xml version="1.0" encoding="UTF-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_home"
android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_home" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav_home"
app:menu="@menu/menu_home_bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
  1. 在 HomeFragment 类中,我使用第二个导航图为 BottomNavigationView 设置了导航流。

[首页片段.kt]

class HomeFragment : Fragment(fragment_home) {
private val viewBinding: FragmentHomeBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val innerNavHostFragment =
childFragmentManager.findFragmentById(R.id.nav_host_fragment_home) as NavHostFragment
val innerNavController = innerNavHostFragment.navController
viewBinding.apply {
NavigationUI.setupWithNavController(bottomNavHome, innerNavController)
}
}
}

我实现的答案有点长,需要你使用谷歌的NavigationExtensions。您可以查看此链接以获取答案。它还包含指向 github 中工作示例的链接。

最新更新