查看原文
其他

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

Android Android 开发者 2021-10-20

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


如果您更倾向于观看视频而非阅读文章,请查看以下视频内容:

△ 导航: 嵌套导航图和 <include>



概述



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


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


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



嵌套导航图



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


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

△ 将 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 以及其他常见资源。


  • 代码
    https://github.com/google-developer-training/android-demos/tree/starter/DonutTracker/NestedGraphs_Include


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

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

coffee 模块依赖 core 模块:

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

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

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

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

△ 导航图没有发生变化

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

https://github.com/google-developer-training/android-demos/tree/main/DonutTracker/NestedGraphs_Include


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



总结



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

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

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



 点击屏末 | 阅读原文 | 即刻了解更多 "嵌套导航图" 相关信息


推荐阅读

如页面未加载,请刷新重试


视频 小程序 ,轻点两下取消赞 在看 ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存