1. 开始之前
导航架构组件Navigation Architecture Component简化了导航的实现,同时也有助于您可视化应用程序的导航流程。该库提供了许多好处,包括
- 自动处理片段事务
- 默认情况下正确处理向上和返回
- 动画和过渡的默认行为
- 将深度链接作为一等操作
- 只需少量额外工作即可实现导航 UI 模式(如导航抽屉和底部导航**)**
- 导航时传递信息时的类型安全
- Android Studio 工具,用于可视化和编辑应用程序的导航流程
您将做什么
在这个 codelab 中,您将使用下面所示的示例应用程序
所有活动和片段都已为您创建。您将使用导航组件连接它们,并在这样做的过程中实现以下内容:
- 可视化导航图
- 按目的地和操作导航
- 过渡动画
- 菜单导航、底部导航和菜单抽屉导航
- 类型安全的参数传递
- 深度链接
先决条件
- Kotlin 基础知识(此 codelab 使用 Kotlin)
- 最新稳定版本的Android Studio以及如何使用它的知识
- 运行 API 19+ 的模拟器或设备
2. 开始
获取代码
从 GitHub 克隆导航 codelab
$ git clone https://github.com/android/codelab-android-navigation
或者,您可以将存储库下载为 Zip 文件
获取最新稳定版本的 Android Studio
确保您使用的是最新版本的 Android Studio。Android Studio 导航工具需要此版本。
如果您需要下载最新版本的 Android Studio,可以点击此处。
导航概述
导航组件由三个关键部分组成,它们和谐地协同工作。它们是:
- 导航图(新的 XML 资源) - 这是一种资源,它在一个集中位置包含所有与导航相关的的信息。这包括应用程序中的所有位置(称为目的地)以及用户可能在应用程序中采取的所有路径。
- NavHostFragment(布局 XML 视图) - 这是添加到布局中的特殊小部件。它显示导航图中的不同目的地。
- NavController(Kotlin/Java 对象) - 此对象跟踪导航图中的当前位置。当您在导航图中移动时,它会协调在
NavHostFragment
中交换目的地内容。
导航时,您将使用 NavController 对象,告诉它您想要去哪里或要在导航图中采取什么路径。NavController
然后将在 NavHostFragment 中显示相应的目的地。
这就是基本思想。让我们看看在实践中它是什么样的,从新的导航图资源开始。
3. 介绍导航图
目的地
导航组件引入了目的地的概念。目的地是您可以在应用程序中导航到的任何位置,通常是片段或活动。这些可以直接使用,但您也可以创建您自己的自定义目的地类型(如果需要)。
导航图
导航图是一种新的资源类型,它定义了用户可以在应用程序中采取的所有可能路径。它以可视方式显示可以从给定目的地到达的所有目的地。Android Studio 在其导航编辑器中显示该图。这是您将为应用程序创建的起始导航图的一部分
探索导航编辑器
- 打开
res/navigation/mobile_navigation.xml
- 点击设计进入设计模式
您应该看到以下内容:
导航图显示可用的目的地。目的地之间的箭头称为操作。稍后您将了解有关操作的更多信息。
- 点击目的地以查看其属性。
- 点击任何操作(用箭头表示)以查看其属性。
导航 XML 文件的结构
您在图形导航编辑器中进行的所有更改都会更改底层的 XML 文件,这类似于布局编辑器修改布局 XML 的方式。
点击文本选项卡
您将看到类似以下内容的 XML 代码:
<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/home_dest">
<!-- ...tags for fragments and activities here -->
</navigation>
注意:
<navigation>
是每个导航图的根节点。<navigation>
包含一个或多个目的地,由<activity>
或<fragment>
元素表示。app:startDestination
是一个属性,它指定用户首次打开应用程序时启动的目的地。
让我们来看一下片段目的地
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
</action>
</fragment>
注意:
android:id
定义片段的 ID,您可以使用它在此 XML 和代码中的其他地方引用该目的地。android:name
声明在导航到该目的地时要实例化的片段的完全限定类名。tools:layout
指定在图形编辑器中应显示哪个布局。
一些<fragment>
标签还包含<action>
、<argument>
和<deepLink>
,我们将在稍后介绍所有这些内容。
4. 向导航图添加目的地
示例应用程序在图中以一些目的地开始。在此步骤中,您将添加一个全新的目的地。您必须先将目的地添加到导航图,然后才能导航到它。
- 打开
res/navigation/mobile_navigation.xml
,然后点击设计选项卡。 - 点击新建目的地图标,然后选择“settings_fragment”
结果是一个新的目的地,它在设计视图中呈现片段布局的预览。
请注意,您也可以直接编辑 XML 文件来添加目的地
mobile_navigation.xml
<fragment
android:id="@+id/settings_dest"
android:name="com.example.android.codelabs.navigation.SettingsFragment"
android:label="@string/settings"
tools:layout="@layout/settings_fragment" />
5. 使用导航图进行导航
现在您有了这个很棒的导航图,但您实际上并没有使用它来导航。
活动和导航
导航组件遵循导航原则中概述的指导。导航原则建议您将活动用作应用程序的入口点。活动还将包含全局导航,例如底部导航,
相比之下,片段将是实际的特定于目的地的布局。
为了使所有这些都能工作,您需要修改您的活动布局以包含一个称为NavHostFragment
的特殊小部件。NavHostFragment
会在您浏览导航图时进出交换不同的片段目的地。
支持导航的简单布局(类似于上图)如下所示。此代码示例可在res/layout-470dp/navigation_activity.xml
中找到
<LinearLayout
.../>
<androidx.appcompat.widget.Toolbar
.../>
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/mobile_navigation"
app:defaultNavHost="true"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</LinearLayout>
注意:
- 这是一个活动布局。它包含全局导航,包括底部导航和工具栏
android:name="androidx.navigation.fragment.NavHostFragment"
和app:defaultNavHost="true"
将系统后退按钮连接到NavHostFragment
app:navGraph="@navigation/mobile_navigation"
将NavHostFragment
与导航图关联。此导航图指定用户可以在此NavHostFragment
中导航到的所有目的地。
NavController
最后,当用户执行点击按钮之类的操作时,您需要触发导航命令。一个名为NavController
的特殊类是触发NavHostFragment
中片段交换的类。
// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)
请注意,您可以传递目的地或操作 ID 来进行导航。这些是在导航图 XML 中定义的 ID。这是一个传递目的地 ID 的示例。
NavController
功能强大,因为当您调用navigate()
或popBackStack()
之类的方法时,它会根据您导航到或来自的目的地类型将这些命令转换为相应的框架操作。例如,当您使用活动目的地调用navigate()
时,NavController
会代表您调用startActivity()
。
有几种方法可以获取与您的NavHostFragment
关联的NavController
对象。在 Kotlin 中,建议您使用以下扩展函数之一,具体取决于您是在片段、活动还是视图中调用导航命令
使用 NavController 导航到目的地
轮到您使用NavController
进行导航。您将连接导航到目的地按钮以导航到flow_step_one_dest
目的地(这是一个FlowStepFragment
目的地)
- 打开
HomeFragment.kt
- 在
onViewCreated()
中连接navigate_destination_button
HomeFragment.kt
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest, null)
}
- 运行应用程序并点击**导航到目的地**按钮。请注意,此按钮会导航到
flow_step_one_dest
目的地。
点击监听器代码如下所示
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.flow_step_one_dest, null)
)
6. 更改导航转换
每个navigate()
调用都带有一个不太令人兴奋的默认转换,如下所示
可以通过包含一组NavOptions
来覆盖默认转换以及与调用关联的其他属性。NavOptions
使用Builder
模式,允许您仅覆盖和设置所需的选项。还有一个用于NavOptions的ktx DSL,这就是您将要使用的。
对于动画转换,您可以在anim
资源文件夹中定义XML动画资源,然后将这些动画用于转换。应用程序代码中包含一些示例
添加自定义转换
更新代码,以便按下**导航到目的地**按钮显示自定义转换动画。
- 打开
HomeFragment.kt
- 定义
NavOptions
并将其传递到对navigate_destination_button
的navigate()
调用中
val options = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
view.findViewById<Button>(R.id.navigate_destination_button)?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest, null, options)
}
- 如果步骤5中添加的代码仍然存在,请将其删除
- 验证点击**导航到目的地**按钮是否会导致片段滑入屏幕,以及按下返回键是否会导致其滑出屏幕
7. 使用操作导航
操作
导航系统还允许您通过*操作*进行导航。如前所述,导航图中显示的行是操作的可视化表示。
通过操作进行导航与通过目的地进行导航相比具有以下优势
- 您可以可视化应用程序中的导航路径
- 操作可以包含您可以设置的其他关联属性,例如转换动画、参数值和回退堆栈行为
- 您可以使用safe args插件进行导航,您很快就会看到
以下是连接flow_step_one_dest
和flow_step_two_dest
的操作的可视化和XML
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
</action>
</fragment>
<fragment
android:id="@+id/flow_step_two_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<!-- ...removed for simplicity-->
</fragment>
注意:
- 操作嵌套在目的地中 - 这是您将从中导航的目的地
- 操作包含一个引用flow_step_two_dest的目的地参数;这是您将导航到的ID
- 操作的ID是“next_action”
这是另一个示例,连接flow_step_two_dest
到home_dest
的操作
<fragment
android:id="@+id/home_dest"
android:name="com.example.android.codelabs.navigation.HomeFragment"
.../>
<fragment
android:id="@+id/flow_step_two_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:popUpTo="@id/home_dest">
</action>
</fragment>
注意:
- 连接
flow_step_two_dest
到home_dest
的操作使用相同的ID next_action。您可以使用来自flow_step_one_dest
或flow_step_two_dest
的next_action id进行导航。这是一个示例,说明操作如何提供抽象级别,并可以根据上下文将您导航到不同的位置。 - 使用了
popUpTo
属性 - 此操作将从回退堆栈中弹出片段,直到您到达home_dest
使用操作导航
是时候连接**使用操作导航**按钮了,让它名副其实!
- 在**设计**模式下打开
mobile_navigation.xml
文件 - 从
home_dest
拖动箭头到flow_step_one_dest
- 选中操作箭头(蓝色)后,更改操作的属性,以便
- ID = next_action
- 进入转换 = slide_in_right
- 退出转换 = slide_out_left
- 弹出进入转换 = slide_in_left
- 弹出退出转换 = slide_out_right
- 点击文本选项卡
请注意home_dest
目的地下新添加的next_action
操作
mobile_navigation.xml
<fragment android:id="@+id/home_dest"
...>
<action android:id="@+id/next_action"
app:destination="@+id/flow_step_one"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
- 打开
HomeFragment.kt
- 向
navigate_action_button
添加点击监听器
HomeFragment.kt
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.next_action, null)
)
- 验证点击**使用操作导航**是否现在导航到下一个屏幕。
8. 使用safe args进行导航
Safe Args
导航组件有一个Gradle插件,称为safe args,它为对为目的地和操作指定的参数进行类型安全访问生成简单的对象和构建器类。
在目的地之间传递值时,safe args允许您摆脱如下所示的代码
val username = arguments?.getString("usernameKey")
并将其替换为具有生成的setter和getter的代码。
val username = args.username
使用safe args传递值
- 打开项目
build.gradle
文件,并注意safe args插件
build.gradle
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
//...
}
- 打开
app/build.gradle
文件,并注意应用的插件
app/build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
//...
}
- 打开
mobile_navigation.xml,
并注意如何在flow_step_one_dest
目的地中定义参数。
mobile_navigation.xml
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="1"/>
<action...>
</action>
</fragment>
使用<argument>
标签,safeargs会生成一个名为FlowStepFragmentArgs
的类。
由于XML包含一个名为flowStepNumber
的参数,由android:name="flowStepNumber"
指定,因此生成的类FlowStepFragmentArgs
将包含一个具有getter和setter的变量flowStepNumber
。
- 打开
FlowStepFragment.kt
- 注释掉下面显示的代码行
FlowStepFragment.kt
// Comment out this line
// val flowStepNumber = arguments?.getInt("flowStepNumber")
这种旧式代码不是类型安全的。最好使用safe args。
- 更新
FlowStepFragment
以使用生成的类FlowStepFragmentArgs
。这将以类型安全的方式获取FlowStepFragment
参数
FlowStepFragment.kt
val safeArgs: FlowStepFragmentArgs by navArgs()
val flowStepNumber = safeArgs.flowStepNumber
Safe Args Direction 类
您还可以使用safe args以类型安全的方式进行导航,无论是否添加参数。您可以使用生成的Directions类来执行此操作。
为每个具有操作的不同目的地生成Directions类。Directions类包含目的地拥有的每个操作的方法。
例如,HomeFragment.kt
中的navigate_action_button
点击监听器可以更改为
HomeFragment.kt
// Note the usage of curly braces since we are defining the click listener lambda
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener {
val flowStepNumberArg = 1
val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
findNavController().navigate(action)
}
HomeFragmentDirections.nextAction(flowStepNumberArg)
9. 使用菜单、抽屉和底部导航进行导航
NavigationUI 和 navigation-ui-ktx
导航组件包含一个NavigationUI
类和navigation-ui-ktx
Kotlin扩展。 NavigationUI
具有将菜单项与导航目的地关联的静态方法,而navigation-ui-ktx
是一组执行相同操作的扩展函数。如果NavigationUI
找到与当前图上的目的地ID相同的菜单项,则它会将菜单项配置为导航到该目的地。
将NavigationUI与选项菜单一起使用
使用NavigationUI最简单的方法之一是让它简化选项菜单设置。特别是,NavigationUI简化了处理onOptionsItemSelected
回调。
- 打开MainActivity.kt
注意您已经在onCreateOptionsMenu
中有了用于膨胀菜单overflow_menu
的代码
- 打开
res/menu/overflow_menu.xml
- 更新您的溢出菜单以包含**
settings_dest
**
overflow_menu.xml
<item
android:id="@+id/settings_dest"
android:icon="@drawable/ic_settings"
android:menuCategory="secondary"
android:title="@string/settings" />
- 打开
MainActivity.kt
- 让NavigationUI使用
onNavDestinationSelected
辅助方法处理onOptionsItemSelected
。如果菜单项不打算导航,则使用super.onOptionsItemSelected
进行处理
MainActivity.kt
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
- 运行您的应用程序。您应该有一个功能齐全的ActionBar菜单,可以导航到SettingsFragment。
使用NavigationUI配置底部导航
代码已经包含了实现底部导航的XML布局代码,这就是为什么您会看到底部导航栏。但它不会导航到任何地方。
- 打开
res/layout/navigation_activity/navigation_activity.xml (h470dp)
并点击**文本**选项卡
注意底部导航的XML布局代码是如何存在的,并且引用了bottom_nav_menu.xml
navigation_activity.xml (h470dp)
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav_menu" />
- 打开
res/menu/bottom_nav_menu.xml
注意底部导航有两个项目,并且**它们的id与**导航图目的地的id**匹配**
bottom_nav_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@id/home_dest"
android:icon="@drawable/ic_home"
android:title="@string/home" />
<item
android:id="@id/deeplink_dest"
android:icon="@drawable/ic_android"
android:title="@string/deeplink" />
</menu>
让我们使用NavigationUI让底部导航真正发挥作用。
- 打开
MainActivity.kt
- 使用
setupWithNavController(bottomNavigationView: BottomNavigationView, navController: NavController)
实现setupBottomNavMenu
方法
MainActivity.kt
private fun setupBottomNavMenu(navController: NavController) {
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
bottomNav?.setupWithNavController(navController)
}
现在您的底部导航可以工作了!
使用NavigationUI配置导航抽屉
最后,让我们使用NavigationUI
配置侧边导航和导航抽屉,包括处理ActionBar和正确的向上导航。如果您屏幕足够大,或者屏幕太短而无法容纳底部导航,您将看到这一点。
首先观察正确的布局XML代码已经在应用程序中了。
- 打开
navigation_activity.xml
和navigation_activity.xml (w960dp)
注意这两个布局都包含一个连接到nav_drawer_menu的NavigationView。在平板电脑版本(w960dp)中,NavigationView始终显示在屏幕上。在较小的设备上,NavigationView嵌套在一个DrawerLayout中。
现在开始实现NavigationView
导航。
- 打开
MainActivity.kt
- 使用
setupWithNavController(navigationView: NavigationView, navController: NavController)
实现setupNavigationMenu
方法。注意此方法版本采用NavigationView
而不是BottomNavigationView
。
MainActivity.kt
private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView?.setupWithNavController(navController)
}
现在导航视图菜单将显示在屏幕上,但它不会影响ActionBar。
设置ActionBar
需要创建一个AppBarConfiguration
的实例。AppBarConfiguration
的目的是指定您希望为工具栏、折叠工具栏和操作栏配置的选项。配置选项包括栏是否必须处理抽屉布局以及哪些目标被认为是**顶级目标**。
顶级目标是应用程序的根级目标。这些目标不会在应用栏中显示“向上”按钮,如果目标使用抽屉布局,则会显示抽屉图标。
- 通过传入一组顶级目标 ID 和抽屉布局来创建一个
AppBarConfiguration
。
MainActivity.kt
val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.home_dest, R.id.deeplink_dest),
drawerLayout)
现在您有了AppBarConfiguration,您可以调用NavigationUI.setupActionBarWithNavController
。这将执行以下操作:
- 根据目标的标签在ActionBar中显示标题
- 当您**不在**顶级目标上时显示向上按钮
- 当您位于顶级目标上时显示抽屉图标(汉堡图标)
- 实现
setupActionBarWithNavController
MainActivity.kt
private fun setupActionBar(navController: NavController,
appBarConfig : AppBarConfiguration) {
setupActionBarWithNavController(navController, appBarConfig)
}
您还应该让NavigationUI处理按下向上按钮时发生的情况。
- 覆盖
onSupportNavigationUp
并调用NavigationUI.navigateUp
,使用相同的AppBarConfiguration
。
MainActivity.kt
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
- 运行您的代码。如果您在分屏模式下打开应用程序,则应该有一个可用的导航抽屉。向上图标和抽屉图标应该在适当的时间显示并正常工作。
向NavigationView
添加新的目标很容易。一旦您使用向上和向后导航使导航抽屉正常工作,您只需要添加新的菜单项即可。
- 打开
menu/nav_drawer_menu.xml
- 为
settings_dest
添加一个新的菜单项
nav_drawer_menu.xml
<item
android:id="@+id/settings_dest"
android:icon="@drawable/ic_settings"
android:title="@string/settings" />
现在您的导航抽屉将设置屏幕显示为目标。干得好!
10. 深度链接到目标
深度链接和导航
导航组件还包括深度链接支持。深度链接是一种跳转到应用程序导航中间的方法,无论是来自实际的URL链接,还是来自通知的挂起意图。
使用导航库处理深度链接的一个好处是,它确保用户从其他入口点(例如应用程序小部件、通知或网络链接(在下一步中介绍))开始时,位于正确的目标并具有相应的返回堆栈。
Navigation 提供了一个NavDeepLinkBuilder
类来构造一个将用户带到特定目标的PendingIntent
。
添加深度链接
我们将使用NavDeepLinkBuilder
将应用程序小部件连接到目标。
- 打开
DeepLinkAppWidgetProvider.kt
- 添加一个使用
NavDeepLinkBuilder
构造的PendingIntent
DeepLinkAppWidgetProvider
val args = Bundle()
args.putString("myarg", "From Widget");
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.mobile_navigation)
.setDestination(R.id.deeplink_dest)
.setArguments(args)
.createPendingIntent()
remoteViews.setOnClickPendingIntent(R.id.deep_link_button, pendingIntent)
注意:
setGraph
包含导航图。setDestination
指定链接的目标位置。setArguments
包含您想要传递到深度链接的任何参数。
- 将深度链接小部件添加到您的主屏幕。长按主屏幕以查看添加小部件的选项。
长按 | 向下滚动查找小部件 |
完成后,您将拥有一个深度链接小部件。
- 点击小部件,并验证 Android 目标是否以正确的参数打开。由于您在 DeepLinkAppWidgetProvider 中传递的参数是“From Widget”,因此顶部应该显示“From Widget”。
- 验证点击后退按钮是否会将您带到
home_dest
目标。
深度链接返回堆栈
深度链接的返回堆栈是使用您传入的导航图确定的。如果您选择的显式 Activity 有一个父 Activity,则这些父 Activity 也包含在内。
返回堆栈是使用app:startDestination
指定的目的地生成的。在这个应用程序中,我们只有一个 Activity 和一个导航级别,因此返回堆栈将带您到home_dest
目标。
更复杂的导航可以包含嵌套导航图。嵌套图的每个级别的app:startDestination
确定返回堆栈。有关深度链接和嵌套图的更多信息,请查看导航原则。
11. 将网络链接与目标关联
<deepLink> 元素
深度链接最常见的用途之一是允许网络链接打开应用程序中的 Activity。传统上,您将使用intent-filter并将 URL 与您要打开的 Activity 关联。
导航库使这变得非常简单,并允许您将 URL 直接映射到导航图中的目标。
<deepLink>
是您可以添加到图中目标的元素。每个<deepLink>
元素都有一个必需属性:app:uri
。
除了直接 URI 匹配之外,还支持以下功能:
- 没有方案的 URI 假定为 http 和 https。例如,
www.example.com
将匹配http://www.example.com
和https://www.example.com
。 - 您可以使用
{placeholder_name}
形式的占位符来匹配一个或多个字符。占位符的字符串值在参数 Bundle 中可用,该参数具有相同的键名。例如,http://www.example.com/users/{id}
将匹配http://www.example.com/users/4
。 - 可以使用通配符
.*
匹配零个或多个字符。 - NavController 将自动处理ACTION_VIEW 意图并查找匹配的深层链接。
使用<deepLink>添加基于 URI 的深层链接
在此步骤中,您将向www.example.com添加一个深层链接。
- 打开
mobile_navigation.xml
- 向
deeplink_dest
目的地添加<deepLink>
元素。
mobile_navigation.xml
<fragment
android:id="@+id/deeplink_dest"
android:name="com.example.android.codelabs.navigation.DeepLinkFragment"
android:label="@string/deeplink"
tools:layout="@layout/deeplink_fragment">
<argument
android:name="myarg"
android:defaultValue="Android!"/>
<deepLink app:uri="www.example.com/{myarg}" />
</fragment>
- 打开
AndroidManifest.xml
- 添加
nav-graph
标签。这将确保生成适当的意图过滤器。
AndroidManifest.xml
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<nav-graph android:value="@navigation/mobile_navigation" />
</activity>
- 使用深层链接启动您的应用。有两种方法可以做到这一点
- 使用
adb
adb shell am start -a android.intent.action.VIEW -d "http://www.example.com/urlTest"
- 通过 Google 应用导航**。**您应该能够将 www.example.com/urlTest 放入搜索栏中,并且会显示消除歧义窗口。选择**导航 codelab**
使用搜索栏打开(不在 Chrome 中) | 消除歧义对话框 |
无论哪种方式,您都应该在屏幕上看到消息“urlTest”。这是从 URL 传递到片段的。
12. [可选] 尝试自行导航
codelab 应用还有一个部分供您尝试,那就是购物车按钮。
这是您在此 codelab 中学习的技能的回顾。此步骤不包含注释,因此请自行尝试。
- 创建一个新的片段类
- 将片段作为目的地添加到导航图中
- 让购物车图标打开您的新片段类,使用 NavigationUI 处理菜单。
13. 恭喜!
您已经熟悉导航组件背后的基本概念!在此 codelab 中,您学习了:
- 导航图结构
- NavHostFragment 和 NavController
- 如何导航到特定目的地
- 如何通过操作导航
- 如何在目的地之间传递参数,包括使用新的 safeargs 插件
- 使用菜单、底部导航和导航抽屉进行导航
- 通过深层链接导航
您可以继续使用此应用进行探索,或者开始在您自己的应用中使用导航。
还有更多内容可以尝试,包括:
- 从返回堆栈中弹出目的地(或任何返回堆栈操作)
- 嵌套导航图
- 条件导航
- 添加对新目的地的支持
有关导航组件的更多信息,请查看文档或Jetpack Compose 导航 Codelab。如果您有兴趣了解其他架构组件,请尝试以下 codelab:
- 带视图的 Room Codelab(LiveData、ViewModel 和 Room)
- Android WorkManager Codelab
- Android 分页 Codelab
- Android 生命周期感知组件 Codelab(LiveData 和 ViewModel)