导航: 嵌套导航图和 <include> | MAD Skills

导航: 嵌套导航图和 <include> | MAD Skills

这是第二个关于导航 (Navigation) 的 MAD Skills 系列,本文是导航组件系列的第三篇文章,如果您想回顾过去发布的内容,请参考下面链接查看:

如果您更倾向于观看视频而非阅读文章,请 点击这里 查看视频内容。

概述

在本系列之前的文章中,我们增加了咖啡记录功能,使用导航 UI 提高了用户体验,并且实现了有条件导航。

在本文中,我们将了解如何通过使用嵌套图管理导航图,并且使用 include 标签来引入其他图。这就需要我们将应用模块化,并且了解导航如何在模块间实现操作。

那么,接下来,让我们打开 Android Studio 开始学习如何在模块上使用导航吧。

嵌套导航图

我们从导航图开始。嵌套图允许您在父导航图中将一系列目的地页面分组。

我们看一眼导航图,coffeeList 和 coffeeEntryDialog 目的地页面非常适合转换为嵌套图。要达成这个目的,我这里长按 shift 并且同时选择 "Move to Nested Graph" (移动到嵌套图):

△ 将 coffeeList 和 coffeeEntryDialogFragment 移动到嵌套图

△ 将 coffeeList 和 coffeeEntryDialogFragment 移动到嵌套图

现在我们回到代码界面,您可以看到嵌套图仅仅是根图中的新导航图:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   app:startDestination="@id/donutList">

   <fragment
       android:id="@+id/donutList"
       android:name="com.android.samples.donuttracker.donut.DonutList"
       android:label="@string/donut_list" >
       <action
           android:id="@+id/action_donutList_to_donutEntryDialogFragment"
           app:destination="@id/donutEntryDialogFragment" />
       <action
           android:id="@+id/action_donutList_to_selectionFragment"
           app:destination="@id/selectionFragment" />
   </fragment>
   <dialog
       android:id="@+id/donutEntryDialogFragment"
       android:name="com.android.samples.donuttracker.donut.DonutEntryDialogFragment"
       android:label="DonutEntryDialogFragment">
       <deepLink app:uri="myapp://navdonutcreator.com/donutcreator" />
       <argument
           android:name="itemId"
           app:argType="long"
           android:defaultValue="-1L" />
   </dialog>
   <fragment
       android:id="@+id/selectionFragment"
       android:name="com.android.samples.donuttracker.setup.SelectionFragment"
       android:label="@string/settings"
       tools:layout="@layout/fragment_selection" >
       <action
           android:id="@+id/action_selectionFragment_to_donutList"
           app:destination="@id/donutList" />
   </fragment>
   <navigation
       android:id="@+id/coffeeGraph"
       app:startDestination="@id/coffeeList">
       <fragment
           android:id="@+id/coffeeList"
           android:name="com.android.samples.donuttracker.coffee.CoffeeList"
           android:label="@string/coffee_list">
           <action
               android:id="@+id/action_coffeeList_to_coffeeEntryDialogFragment"
               app:destination="@id/coffeeEntryDialogFragment" />
       </fragment>
       <dialog
           android:id="@+id/coffeeEntryDialogFragment"
           android:name="com.android.samples.donuttracker.coffee.CoffeeEntryDialogFragment"
           android:label="CoffeeEntryDialogFragment">
           <argument
               android:name="itemId"
               android:defaultValue="-1L"
               app:argType="long" />
       </dialog>
   </navigation>
</navigation>

所选择的 Fragment 之间的导航被迁移至嵌套图中。

嵌套图必须包含 id。您可以使用这个 id 实现导航到嵌套图的代码,但并不是直接转换到其子目的地页面。嵌套图包含自己的启动目的地页面,并且请不要分开暴露它们的子目的地页面。

<navigation
   android:id="@+id/coffeeGraph"
   app:startDestination="@id/coffeeList">

如果您双击嵌套图,就可以发现嵌套的目的地页面和它们之间的操作。

Include 标签

除了使用嵌套图之外,我还可以提取图到新的导航 xml 文件中。我在这里创建了一个新的 xml 文件,名称为 coffee_graph,并且将嵌套图的内容迁移到这个文件中。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/coffeeGraph"
   app:startDestination="@id/coffeeList">
   <fragment
       android:id="@+id/coffeeList"
       android:name="com.android.samples.donuttracker.coffee.CoffeeList"
       android:label="@string/coffee_list">
       <action
           android:id="@+id/action_coffeeList_to_coffeeEntryDialogFragment"
           app:destination="@id/coffeeEntryDialogFragment" />
   </fragment>
   <dialog
       android:id="@+id/coffeeEntryDialogFragment"
       android:name="com.android.samples.donuttracker.coffee.CoffeeEntryDialogFragment"
       android:label="CoffeeEntryDialogFragment">
       <argument
           android:name="itemId"
           android:defaultValue="-1L"
           app:argType="long" />
   </dialog>
</navigation>

我可以通过 include 标签将新的图嵌套到其他文件中。虽然使用 include 标签在功能上与使用嵌套图相同,但您还可以使用其他项目模块或者库项目的图。

<include app:graph="@navigation/coffee_graph"/>

和嵌套图相类似,引用的图不会暴露目的地页面的列表,也就是说我需要更新菜单 id 来指向 coffeeList。

<item
   android:id="@id/coffeeGraph"
   android:icon="@drawable/coffee_cup"
   android:title="@string/coffee_name" />

这里我更新了菜单以使用引用图的 id。由于 CoffeeList 是所引用图的起始页面,所以我可以使用图 id 来导航到这个图。如果您现在试着运行应用,所有的功能会和之前一样。

现在咖啡记录的导航图已经实现分离,我们可以对应用进行模块化处理,顺便可以看一下在模块之间导航的效果如何。

如果您希望同步操作,可以检查 代码,里面包含了到目前为止我所做的全部修改。我创建了两个新的模块: core 和 coffee。我将所有常用的类迁移到 core 模块中,比如 Donut、Coffee、DAO、Database 以及其他常见资源。

接下来,我将所有在咖啡记录中用到的 fragment、viewModel 和 adapter 类迁移到 coffee 模块中。在咖啡记录中用到的布局和其他资源也迁移到这里,包括 coffee_graph。

△ 已有的类和资源被迁移到了 core 和 coffee 模块中

△ 已有的类和资源被迁移到了 core 和 coffee 模块中

coffee 模块依赖 core 模块:

dependencies {

   implementation project(":core")

   //...
}

最后,在 app 模块中,添加 coffee 和 core 作为 app 模块的依赖:

dependencies {
   implementation project(":coffee")
   implementation project(":core")
   //..
}

请注意这里的导航图没有任何变化,它不受这些修改的影响:

△ 导航图没有发生变化

△ 导航图没有发生变化

现在如果运行应用,所有的功能一如往常,只不过内部使用了模块。您可以查看 最终的代码

通过上述修改,我将咖啡记录模块和与它相关的导航流从应用中分离了出来,也就意味着咖啡记录模块可以独立于甜甜圈记录应用使用。

总结

在本文中,我们了解了如何创建嵌套导航图,以及如何使用 include 标签来模块化甜甜圈记录应用。

在下一篇文章中,我们会更进一步学习如何使用功能模块进行导航。敬请关注!

欢迎您通过下方二维码向我们提交反馈,或分享您喜欢的内容、发现的问题。您的反馈对我们非常重要,感谢您的支持!

版权声明

禁止一切形式的转载-禁止商用-禁止衍生 申请授权

脉脉不得语
脉脉不得语
Zhengzhou Website
Android Developer | https://androiddevtools.cn and https://androidweekly.io Funder | GDG Zhengzhou Funder & Ex Organizer | http://Toast.show(∞) Podcast Host

你已经成功订阅到 Android 开发技术周报
太棒了!接下来,完成检验以获得全部访问权限 Android 开发技术周报
欢迎回来!你已经成功登录了。
Unable to sign you in. Please try again.
成功!您的帐户已完全激活,您现在可以访问所有内容。
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.
🍗