乐趣区

关于android:使用导航组件-对话框目的地-MAD-Skills

这是一个新的系列文章,咱们称之为 “Modern Android Development 技巧 ”,简称为 “MAD Skills”。本系列文章致力于帮忙开发者们打造更好的古代 Android 开发体验,敬请关注。

明天为大家公布本系列文章中的第二篇: 导航到对话框目的地,如果您想理解第一篇公布的内容,请点击这里查看本系列的第一篇: 导航组件概览。

概览

在本系列的 上一篇文章 中,我大抵介绍了导航组件以及如何应用导航图。

在这篇文章中,我会介绍如何应用 API 来导航到对话框目的地 (dialog destination)。大部分的导航产生在 Fragment 目的地之间,在 UI 中的 NavHostFragment 对象外部,fragment 会被替换进来。但其实导航到容器外的目的地包含对话框也是可行的。就像咱们实现一般的目的地一样,咱们也能够应用导航图来实现导航到对话框目的地。

甜甜圈记录利用

我有一个小麻烦: 我超爱甜甜圈。

我心愿能记得之前吃的哪些甜甜圈是好吃的,这样下次我就能够再买它们。而对于那些我不喜爱的,我也能够防止再买到它们。但我很健忘,所以问题来了,我如何能力记录如此重要的数据呢?

我晓得了: 我要用一个利用!

惋惜的是,我居然在 Play 商店中找不到一个甜甜圈记录的利用 (太不堪设想了)。所以我只能本人写一个利用。这个利用会有一个我所有吃过甜甜圈的列表,也包含我记录下的对于它们每一个的信息,比方名字、介绍、或者还有一张照片以及相应的评分。

这将是一个相当简略的利用,它包含两个页面:

  • 一个甜甜圈列表页
  • 一个能够输出甜甜圈相干信息的表单页,它既能够是对于我要新增到列表中的甜甜圈,也能够是对于我要编辑的已存在列表中的甜甜圈

至于信息编辑页面,我心愿能用一个对话框。我想实现在以后 activity 上弹出一个绝对轻量级的弹窗,而不是替换掉整个页面。我晓得导航组件能够解决目的地,然而那只能替换掉单个 NavHostFragment 中的 fragment,对吗?

对,也不对。导航组件默认的行为的确是替换掉 NavHostFragment 中的 fragment。然而导航组件同样能够解决在 NavHostFragment 之外的对话框目的地。

通过模版创立一个工程

首先,我会展现如何在一个新利用中设定导航的根本元素。而后,我会展现我曾经写好的甜甜圈记录利用,这样您能够大抵理解这将是一个怎么的利用。(我叫这个为 Julia Child 技巧。在她多年前的烹饪节目中,Child 女士会先介绍菜谱,紧接着疾速地展现实现的菜品,最初才是筹备工作以及烹饪等两头简短乏味的局部)

从 Android Studio 3.6 当前,您能够抉择任一新建工程模版来应用导航组件。我发现这样做很不便,即使我最终的界面跟模版利用基本不像,至多模版会帮我解决相似下载适合的依赖,以及创立根底代码和资源等工作。

一开始咱们须要在 Android Studio 中创立一个 Basic Activity。这一步我在 上一篇文章 中都介绍过,您能够查阅并获取更多详细信息。这里咱们将间接跳到下一步。

对话框目的地

如果留神察看导航图中咱们新建的 basic activity,您会发现利用此时有两个目的地,同时也包含了在它们彼此之间跳转的操作 (action)。这两个目的地都是 fragment,模版帮咱们实现了在 NavHostFragment 外部替换它们的操作。

Basic Activity 附带两个 fragment 以及在它们之间导航的操作

这基本上就是所有咱们须要的,所差的是咱们须要目的地是一个咱们能够输出甜甜圈详细信息的对话框。为了创立这个目的地,首先咱们创立所须要的对话框类。

首先,咱们在 UI 中创立一个带文本占位符的布局。在布局资源文件夹下创立一个名为 my_dialog.xml 的文件。而后在这个布局中,增加一个 TextView 并且限度它的四边边距使其放弃在容器的正中间。后果应该看起来像下图:

咱们创立的简略对话框,包含一个居中的文本占位符

接下来,创立一个 Fragment 用来加载下面创立的布局。在 main 包中创立一个新的 Kotlin 文件并命名为 MyDialog.kt。在该文件中,创立一个继承自 BottomSheetDialogFragment 的子类 MyDialog,并且重写 onCreateView() 以返回一个加载自咱们刚刚创立的布局的视图。

class MyDialog : BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.my_dialog, 
            container, false)
    }
}

咱们曾经失去了对话框 fragment,当初能够创立一个能够导航到它的目的地。让咱们回到导航图并新增一个目的地。在弹出的菜单中,您应该能够发现零碎曾经辨认出 MyDialog,选中它。

选中列表中的 MyDialog 作为新的目的地,并且确保它是一个 “ 对话框 ” 而不是一个 “Fragment”

长于察看的读者可能会从下面截图中发现一个 IDE 的小 bug。只管 MyDialog 事实上是一个 Dialog 对象,导航工具有时候不能精确地辨认进去,而把它增加为一个 Fragment 目的地。这个后果绝不是咱们所冀望的。尽管它并不是常常产生 (好吧,呈现了不可预期的后果),然而在我开发这个示例的过程中曾经呈现了屡次这个问题,所以在这里我心愿强调一下。它的确很容易让人蛊惑。还好,解决办法也非常简单,所以大家这里只须要晓得有可能会呈现这样的问题就能够了。

如果您碰到了这个问题,间接去导航图的 XML 代码中将 fragment 标签改成 dialog,就能够解决这个问题。这是我解决这个问题之后的代码:

<dialog
    android:id=”@+id/myDialog”android:name=”com.android.samples.navdialogsample.MyDialog”android:label=”MyDialog”/>

另外,我曾经就这个问题征询了 Android Studio 团队。据说这个问题是因为外部依赖搜寻的程序导致的。他们正在修复这个问题。

对话框的目的地当初曾经筹备好了,接下来咱们能够创立一个从主界面跳转到对话框目的地的操作:

创立一个新的从 FirstFragment 导航到对话框的操作

咱们还须要额定的一步才可能导航到这个对话框。在 FirstFragment 的代码中,有一段代码 (Basic Activity 模版主动创立的) 解决了按钮点击事件并导航到 SecondFragment 目的地:

view.findViewById<Button>(R.id.button_first).setOnClickListener {findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}

咱们只需应用适当的 id 将导航目的地扭转为对话框,这里的 id 正是在导航图中创立目的地时所生成的。

view.findViewById<Button>(R.id.button_first).setOnClickListener {findNavController().navigate(R.id.action_FirstFragment_to_myDialog)
}

功败垂成!终于能够运行咱们的利用来看看实际效果了。当咱们点击按钮的时候,它会如期地带咱们去那个对话框目的地。

点击按钮会关上一个十分高大的带有文本占位符的对话框

您可能留神到对话框显示的尺寸要远比它在设计工具中看起来小得多 — 这是因为这个对话框的内容只有那个 TextView 占位符作为内容。但请置信我,那就是咱们的对话框。

咱们刚创立的其实是我想要的甜甜圈记录利用的一个绝对简化的版本,只是想通过它来展现如何创立以及应用对话框作为目的地的根本步骤。接下来,让咱们看一下甜甜圈利用的理论代码。

DonutTracker 利用实际

“ 剧透 ” 正告: 我曾经写完了 DonutTracker 利用。我会带您浏览要害的实现步骤,大家能够看到我是如何应用对话框目的地导航的。

首先,这是利用的导航图:

在 DonutTracker 的导航图中有两个目的地

您会发现主页目的地仍然存在,只不过叫做 donutList。这是那个蕴含甜甜圈列表 (应用 RecyclerView) 的 fragment。我还创立了第二个目的地,叫做 donutEntryDialogFragment,这个是用来让用户编辑甜甜圈信息的。

如果咱们查看 DonutList 的代码,该 fragment 蕴含了那个展现列表数据的 RecyclerView,咱们能够发现导航是如何被解决的。点击 FloatingActionButton (FAB) 按钮触发了导航到对话框:

binding.fab.setOnClickListener { fabView ->
    fabView.findNavController().navigate(DonutListDirections
        .actionDonutListToDonutEntryDialogFragment())
}

留神我这里用的是 视图绑定 来获取 FloatingActionButton 的援用,也即 binding.fab 的援用。

除此之外,咱们同样能够在这个文件中看到点击 RecyclerView 中的列表项是如何导航到编辑那一项的对话框的:

donut ->
    findNavController().navigate(DonutListDirections
        .actionDonutListToDonutEntryDialogFragment(donut.id))

对于上述代码片段,有几点须要留神:

首先,咱们在此应用的 navigate() 函数 (应用 Directions 对象导航 ) 的语法和之前通过 Basic Activity 模版创立的 (导航到一个通过 R.id.action_FirstFragment_to_myDialog 指定的操作 ) 略有不同。这是因为上述代码片段来自于 DonutTracker 利用的最终版本,在该版本中我应用了 SafeArgs。SafeArgs 能够生成 Directions 代码,这使得目的地之间带有参数传递的跳转实现起来更加容易。

其次,咱们从 FAB 导航时 (不须要传递参数给 Directions 对象) 调用 navigate() 办法和从甜甜圈列表中任一列表项导航时 ( 须要传递 donut.id) 不太一样。这个区别能够让咱们决定到底是创立一个新甜甜圈 (当没有传递参数) 还是编辑已有的甜甜圈 (当传递了 donut.id)。(剧透正告: 我会在接下来的文章中介绍这一主题,您也能够同时查阅 残缺代码 。)

运行该利用展现了它是如何工作的。如您所见,我曾经事后在利用中输出了一些重要的甜甜圈数据:

DonutTracker 利用展现着一个迷人的甜甜圈列表

点击 FAB,咱们能够看到一个待输出新甜甜圈信息的对话框:

点击 FAB 导航到输出新甜甜圈信息的对话框目的地

如果咱们点击任一已存在的甜甜圈 (这里我点击了 “fundonut”,因为很显然这里的形容须要再润色一下),利用会带咱们到同一个对话框目的地,在这里咱们能够编辑刚刚点击的甜甜圈的信息。

点击任一甜甜圈会导航到编辑其信息的对话框

点击 DONE 按钮,将保留更改到数据库中并且返回更新的列表;而点击 CANCEL 按钮,将放弃掉所有的编辑并返回。留神: 点击返回按钮,同样会返回甜甜圈列表,因为导航组件曾经主动为咱们设置好了返回栈。

总结

通过这篇文章咱们理解了如何应用内置的导航组件疾速地创立一个新利用,并且学习了如何导航到对话框目的地。在接下来的文章中,咱们会持续通过开发这个利用为大家展现导航组件的其它性能,当然也同时会实现一个性能更加弱小的甜甜圈记录利用。

更多信息

更多对于导航组件的详情,请查看 导航组件应用入门文档

DonutTracker 利用的残缺代码,请查看 Github 示例

更多 MAD Skills 系列内容,请查看 Android Developers 频道

退出移动版