一、Android Jetpack_Note_CodeLabs一Navigation

3,521 阅读10分钟

1、简介

Navigation简化了导航的实现,同时也帮助您可视化应用程序的导航流,Naviagtion组件提供了以下的功能:

  1. 自动处理Fragment碎片事务
  2. 默认处理返回键和上一步的操作
  3. 动画和过渡的默认行为
  4. 默认页面以及下一层的链接操作
  5. 用很少的代码去实现导航界面(例如导航抽屉和地步导航)
  6. 导航切换界面之间的参数传递
  7. 在Android Studio中一个可视化的Navigation操作界面

1.1 你需要做什么?

Codelab中你可以使用demo运行效果:

所有的Activity和Fragment都已经为你创建好了,你可以使用导航组件连接它们,并在连接过程中实现以下功能:

  1. 一个可视化的Navigation编辑器
  2. 设计导航的目的地和Action
  3. 切换动画
  4. Menu菜单、底部导航栏以及DrawLayout侧边栏按钮
  5. 类型安全的参数传递
  6. 深层次的链接

1.2 使用条件

  • 基本Kotlin知识(codelab中代码使用Kotlin)
  • Android Studio 3.2以上
  • API 14+

2、入门

2.1 获取代码

Github

$ git clone https://github.com/googlecodelabs/android-navigation

2.2 Navigation 概述

Navigation组件主要包括三个部分

  1. Navigation Graph (一种新版的XML文件),是一个集中包含了所有Navigation相关的信息的一种新版的XML文件。它包括app中的所有界面(Activity或Fragment),以及用户可以通过app访问的可能路径。
  2. NavHostFragment (Layout XML view),这是一个添加到布局中的特殊部件。avHostFragment通过navGraph与navigation导航编辑器进行关联.
  3. NavController(Kotlin/Java object),这是一个跟踪导航图中当前位置的对象,当您在导航图中移动时,它协调交换navhostfragment中的目标内容。

当你导航时,你将使用导航控制器对象,告诉它你想去哪里,或者你想在你的导航图中走什么路径。然后,导航控制器将在NavHostframent中显示适当的目的地。

这是基本的想法。让我们从新的导航图资源开始,看看这在实践中是什么样子的。

3、Navigation Graph

3.1 Destinations

Navigation组件中有一个Destinations的概念,它是一个可以在你APP中导航到的任意的地方,通常是一个Activity或者Fragment,默认是支持使用的,如果你需要你可以自己自定义目标类型。

3.2 Navigation Graph

一个导航图是一种新的资源类型,它直观地显示从给定目的地可以到达的所有目的地。在AS的Navigation Editor中展示,下面是为APP创建的起始导航图的一部分:

3.3 Navigation Editor

  1. 打开res/navigation/mobile_navigation.xml文件
  2. 点击 Desgin 进入设计模式

接下来你可以看到:

视图向我们展示了会用到的目标页面,视图中的箭头我们叫做action,下面会详细介绍

  1. 点击一个目标界面查看属性

  1. 点击任意的一个箭头的Action,查看属性

3.4 Navigation XML 解析

在设计模式下你对导航的设计改变都可以在XML布局文件中看到,点击Text按钮

你可以看到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属性
  • ndroid:name是你的目标界面的整个包路径名
  • tools:layout 指定应在图形编辑器中显示的布局

代码中的<action> <argument>下面会详细介绍

4、为导航视图添加一个目标界面

demo中只有很少的目标接 main,下面我们可以新增一个目标界面,首先你需要自己先创建好一个Fragment或者Activity:

每一步的代码都在demo中可以找到,你可以在TODO的地方编写代码或与注释掉的代码进行比较

  1. 打开res/navigation/mobile_navigation.xml文件,点击Desgin按钮
  2. 点击新建按钮,选择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" />

要遵循我们的命名约定,请将ID从默认设置片段更改为SettingsFragment

5、使用Navigation Graph导航一个页面

5.1 界面和导航

Navigation组件遵循导航原则中Navigation指南,指南中建议您使用activities作为APP的入口,activities包括普通的Navigation例如:BottomNavigation。相比较下,fragment一版作为一个目标界面。

接下来你需要在布局中新增NavHostFragment,NavHostFragment通过navGraph与navigation导航编辑器进行关联

<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>

注意

  • 这是一个Activity,它包含了一个普通的Navigation、和一个底部导航以及一个Toobar
  • android:name="androidx.navigation.fragment.NavHostFragment"app:defaultNavHost="true"通过NavHostFragment连接系统返回键
  • app:navGraph="@navigation/mobile_navigation"通过NavHostFragment连接导航的菜单按钮,导航视图可以通过NavHostFragment导航到任意的目标界面

5.2 NavController

最后,当你点击一个按钮时,你需要触发一个导航命令。Navcontroller的触发navhostfragment中的fragemnt切换。

// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)

注意您输入要导航的目标或操作ID,这些ids是你在xml布局中定义好的。NavController是很强大的,你可以调用navigate()或者popBackStack()它可以将代码转化为匹配的导航操作,这些操作基于您要导航的目标类型。例如:你可以调用navigate()去跳转到一个目标界面,NavConroller会调用自身的startActivity()

Kotlin中提供了扩展函数可以获得与NavHostFragment关联的NavController对象:

  • Fragment.findNavController()
  • view.findNavController()
  • Activity.findNavController(viewId: Int)

你的NavController和一个NavHostFragment相关联。因此无论使用哪种方法,都必须保证fragmengt,view或者view id是NavHostFragmengt本身,或者是它的父类。否则将会抛出异常。

5.3 使用NavController切换页面

你可以使用NavController去切换FlowStepFragment

  1. 打开HomeFragment.kt
  2. onViewCreated() 中find navigate_destination_button
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
    findNavController().navigate(R.id.flow_step_one_dest, null)
}
  1. 运行APP点击Navigate To Destination按钮,请注意,该按钮导航到flow_step_one_dest目的地

您也可以使用便捷方法Navigation.createNavigateOnClickListener(@IdRes destId: int, bundle: Bundle)。此方法将构建一个OnClickListener导航到给定目标,并使用一组参数传递给目标。

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动画资源,然后将这些动画用于过渡。应用代码中包含一些示例:

6.1 添加自定义过渡

更新代码,以便按导航到目标按钮显示自定义过渡动画。

  1. 打开 HomeFragment.kt
  2. 定义NavOptions并将其传递给navigate()调用navigate_destination_button
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)
}
  1. 删除步骤5中添加的代码(如果它仍然存在)
  2. 确认点击“ 导航到目的地”按钮会导致片段滑动到屏幕上,然后按下该片段会使其滑出屏幕

7、使用操作导航Action

7.1 Actions

导航系统还允许您通过Actions进行导航。如前所述,导航图中显示的线条是动作的直观表示。

按行动导航比目标导航具有以下优势:

  • 您可以通过应用程序可视化导航路径
  • 操作可以包含您可以设置的其他关联属性,例如转换动画,参数值和Backstack行为
  • 您可以使用插件安全args进行导航,您很快就会看到

这是连接的操作的可视化和XML,flow_step_one_dest并且flow_step_two_dest

<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_desthome_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>

注意:

  • 相同的ID next_action用于连接作用flow_step_two_desthome_dest。您可以导航使用next_action ID从任一flow_step_one_destflow_step_two_dest。这是一个示例,说明操作如何提供抽象级别,并可以根据上下文导航到不同的位置。 使用该popUpTo属性 - 此操作将从后栈中弹出片段,直到您到达home_dest

7.2 使用Action进行导航

  1. mobile_navigation.xml在设计模式下打开文件
  2. 从拖动箭头home_destflow_step_one_dest

  1. 选择操作箭头(蓝色)更改操作的属性,以便:
  • ID = next_action
  • 转换为Enter = slide_in_right
  • Exit = slide_out_left的转换
  • Pop Enter的转换= slide_in_left
  • Pop Exit的过渡= slide_out_right

  1. 单击**“文本”**选项卡 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" />
  1. 打开HomeFragment.kt
  2. 添加一个单击监听器 navigate_action_button HomeFragment.kt
 view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
        Navigation.createNavigateOnClickListener(R.id.next_action, null)
)

操作允许您附加NavOptions在导航XML文件中,而不是以编程方式指定它们。

  1. 确认点击导航到操作现在导航到下一个屏幕。

8、使用安全args进行导航

8.1 安全的Args

导航组件有一个名为safe args的Gradle插件,它生成简单的对象和构建器类,以便对为目标和操作指定的参数进行类型安全访问。

Safe args允许您在目标之间传递值时删除这样的代码:

val username = arguments?.getString("usernameKey")

而是将其替换为生成setter和getter的代码。

val username = args.username

由于其类型安全性,使用安全args生成类的导航是通过操作导航并在导航期间传递参数的首选方式。

8.2 使用安全args传递值

  1. 打开项目build.gradle文件并注意safe args插件:

build.gradle

dependencies {
        classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    //...
    }
  1. 打开app/build.gradle文件并注意应用的插件:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs'

android { 
   //...
}
  1. 打开mobile_navigation.xml,并注意如何在flow_step_one_dest目标中定义参数
<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将包含一个flowStepNumber带有getter和setter 的变量。

  1. 打开 FlowStepFragment.kt
  2. 注释掉下面显示的代码行 FlowStepFragment.kt
/ Comment out this line
// val flowStepNumber = arguments?.getInt("flowStepNumber")

这种旧式代码不是类型安全的。最好使用安全的args。 6. 更新FlowStepFragment以使用代码生成的类FlowStepFragmentArgs。这将以FlowStepFragment类型安全的方式获取参数:

FlowStepFragment.kt

val safeArgs: FlowStepFragmentArgs by navArgs()
val flowStepNumber = safeArgs.flowStepNumber

8.3 安全Args方向类

您还可以使用安全args以类型安全的方式导航,无论是否添加参数。您可以使用生成的Directions类来完成此操作

通过操作为每个不同的目标生成方向类。Directions类包含目标具有的每个操作的方法。

例如,navigate_action_buttonHomeFragment.kt中的单击侦听器可以更改为:

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)
}

请注意,在导航图XML中,您可以defaultValue为每个参数提供一个。如果你没有,那么你必须传递参数到动作,如图所示: HomeFragmentDirections.nextAction(flowStepNumberArg)

9、使用菜单,抽屉和底部导航进行导航

9.1 NavigationUI和navigation-ui-ktx

导航组件包括一个NavigationUI类navigation-ui-ktxkotlin扩展。NavigationUI具有将菜单项与导航目的地相关联的静态方法,并且navigation-ui-ktx是一组执行相同操作的扩展函数。如果NavigationUI在当前图形上找到与目标ID相同的菜单项,则会将菜单项配置为导航到该目标

9.2 将NavigationUI与选项菜单一起使用

使用NavigationUI的最简单方法之一是简化选项菜单设置。特别是,NavigationUI简化了onOptionsItemSelected回调的处理。

  1. 打开MainActivity.kt

请注意,你怎么已经有代码膨胀的菜单overflow_menuonCreateOptionsMenu

  1. 打开 res/menu/overflow_menu.xml

  2. 更新溢出菜单以包含 settings_dest

overflow_menu.xml

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:menuCategory="secondary"
    android:title="@string/settings" />
  1. 打开 MainActivity.kt

  2. onOptionsItemSelected使用onNavDestinationSelected辅助方法处理NavigationUI句柄。如果菜单项不是要导航,请使用super.onOptionsItemSelected

MainActivity.kt

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
            || super.onOptionsItemSelected(item)
}
  1. 运行您的应用程序。您应该有一个功能的ActionBar菜单导航到SettingsFragment。

9.3 使用NavigationUI配置底部导航

代码已经包含用于实现底部导航的XML布局代码,这就是您看到底部导航栏的原因。但它不会导航到任何地方。

  1. 打开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" />
  1. 打开 ````res/menu/bottom_nav_menu.xml``` 请注意底部导航有两个项目,它们的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做一些事情。

  1. 打开 MainActivity.kt

  2. setupBottomNavMenu使用实现方法setupWithNavController(bottomNavigationView: BottomNavigationView, navController: NavController)

MainActivity.kt

private fun setupBottomNavMenu(navController: NavController) {
    val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
    bottomNav?.setupWithNavController(navController)
}

9.4 使用NavigationUI配置导航抽屉

最后,让我们使用NavigationUI配置侧面导航和导航抽屉,包括处理ActionBar和正确的导航。如果您有足够大的屏幕或者屏幕太短而无法进行底部导航,您会看到这一点。

首先观察应用程序中已有适当的布局XML代码。

  1. 打开navigation_activity.xml和navigation_activity.xml (w960dp)

请注意两个布局如何包含连接到nav_drawer_menu 的NavigationView。在平板电脑版本(w960dp)中,NavigationView始终在屏幕上。在较小的设备上,NavigationView 嵌套在DrawerLayout中。

现在开始实施NavigationView导航。

  1. 打开 MainActivity.kt

  2. setupNavigationMenu使用实现方法setupWithNavController(navigationView: NavigationView, navController: NavController)。请注意该方法的版本如何使用NavigationView而不是a BottomNavigationView。

MainActivity.kt

private fun setupNavigationMenu(navController: NavController) {
    val sideNavView = findViewById<NavigationView>(R.id.nav_view)
    sideNavView?.setupWithNavController(navController)
}

现在导航视图菜单将显示在屏幕上,但不会影响ActionBar。

设置ActionBar需要创建一个实例AppBarConfiguration。目的AppBarConfiguration是为工具栏,折叠工具栏和操作栏指定所需的配置选项。配置选项包括栏是否必须处理抽屉布局以及哪些目的地被视为顶级目的地。

顶级目标是应用程序的根级目标。这些目的地不会在应用栏中显示“向上”按钮,如果目的地使用抽屉布局,它们会显示抽屉图标。

  1. AppBarConfiguration通过传递一组顶级目标ID和抽屉布局来创建。

MainActivity.kt

val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
        setOf(R.id.home_dest, R.id.deeplink_dest),
        drawerLayout)

如何确定顶级目的地 通过全局导航UI可到达的目的地,例如底部导航或侧面导航,所有目标都显示给用户,因为它们位于层次结构的同一顶层。因此,它们是顶级目的地。home_dest并且deeplink_dest在底部导航中,我们希望抽屉图标显示在这两个目的地上,因此它们是顶级目的地。 请注意,起始目标始终被视为顶级目标。如果未指定顶级目标列表,则唯一的顶级目标是您的起始目标。您可以AppBarConfiguration在文档中了解更多信息。

5.实施 setupActionBarWithNavController

MainActivity.kt

private fun setupActionBar(navController: NavController,
                           appBarConfig : AppBarConfiguration) {
    setupActionBarWithNavController(navController, appBarConfig)
}

您还应该让NavigationUI处理按下向上按钮时发生的情况。

  1. 覆盖onSupportNavigationUpNavigationUI.navigateUp使用相同的呼叫AppBarConfiguration

MainActivity.kt

override fun onSupportNavigateUp(): Boolean {
    return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
  1. 运行您的代码。如果您在拆分屏幕中打开应用程序,则应该有一个可用的导航抽屉。向上图标和抽屉图标应在适当的时间显示并正常工作。

布局navigation_activity.xml(h470dp)将在纵向模式下在手机上使用。这种布局也未包含该导航抽屉,而是包括底部导航,这就是为什么你要在分屏打开应用程序,看看抽屉式导航栏。没有导航抽屉和底部导航布局的原因是因为Material Design准则警告不要这样做。

添加新目的地NavigationView很容易。导航抽屉使用向上和向后导航后,只需添加新菜单项即可。

  1. 打开menu/nav_drawer_menu.xml

9.添加新菜单项 settings_dest

nav_drawer_menu.xml

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:title="@string/settings" />

10、深度链接到目的地

10.1 深层链接和导航

导航组件还包括深层链接支持。深层链接是一种跳入应用导航中间的方式,无论是来自实际的URL链接还是来自通知的待处理意图。

使用导航库处理深层链接的一个好处是,它可以确保用户使用来自其他入口点(如应用程序小部件,通知或Web链接)的相应后备堆启动正确的目标(在下一步中介绍)。

导航提供了一个NavDeepLinkBuilder类来构建一个PendingIntent将用户带到特定目的地的类

10.2 添加深层链接

我们将使用将NavDeepLinkBuilderapp小部件连接到目标。

1.打开 DeepLinkAppWidgetProvider.kt

2.添加一个PendingIntent构造NavDeepLinkBuilder

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 包括您要传递到深层链接的任何参数。

默认情况下NavDeepLinkBuilder将启动您的启动器活动。您可以通过将活动作为上下文传递或通过设置显式活动类来覆盖此行为setComponentName()

  1. 将Deep Link小部件添加到主屏幕。点击并按住主屏幕以查看添加小部件的选项

完成后,您将拥有一个深层链接小部件。

4. 点击窗口小部件,并验证Android目标是否以正确的参数打开。它应该在顶部说“From Widget”,因为那是你在DeepLinkAppWidgetProvider中传递的参数

  1. 确认按下后退按钮将您带到home_dest目的地。

为方便起见,你也可以调用NavController的createDeepLink()方法使用Context从当前和导航图NavController。

10.3 DeepLink Backstack

使用您传入的导航图确定深层链接的后台堆栈。如果您选择的显式活动具有父活动,则还包括这些父活动。

使用指定的目标生成backstack app:startDestination。在这个应用程序中,我们只有一个活动和一个级别的导航,因此backstack将带您到home_dest目的地。

更复杂的导航可以包括嵌套导航图。的app:startDestination在嵌套图的每个水平决定返回堆栈。有关深层链接和嵌套图形的更多信息,请查看导航原理

11、 将Web链接与目标关联

11.1 元素

深层链接最常见的用途之一是允许Web链接在您的应用中打开活动。传统上,您将使用intent-filter并将URL与您要打开的活动相关联。

导航库使这非常简单,并允许您将URL直接映射到导航图中的目标。

是您可以添加到图表中目标的元素。每个元素都有一个必需的属性:app:uri。

除了直接URI匹配外,还支持以下功能:

  • 没有方案的URI被假定为http和https。例如,www.example.com将匹配http://www.example.com和https://www.example.com。
  • 您可以使用形式{placeholder_name}匹配一个或多个字符的占位符。占位符的String值在参数Bundle中可用,该参数具- 有相同名称的键。例如,www.example.com/users/{id}将…
  • 您可以使用.*通配符匹配零个或多个字符。
  • NavController将自动处理ACTION_VIEW意图并寻找匹配的深层链接

11.2 使用添加基于URI的深层链接

在此步骤中,您将添加指向www.example.com的深层链接。

  1. 打开 mobile_navigation.xml

  2. 将元素添加到deeplink_dest目标。

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>
  1. 打开 AndroidManifest.xml

  2. 添加nav-graph标签。这将确保生成适当的intent过滤器

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>

如果您想知道生成了什么,可以在输出APK中找到结果。 在项目视图中,导航到app - > build - > outputs - > apk - > debug - > app-debug.apk 双击app-debug.apk以在APK Analyzer中打开。在这里,您将能够看到生成的AndroidManifest。

  1. 使用深层链接启动您的应用。有两种方法可以做到这一点:
  • 用途adb

adb shell am start -a android.intent.action.VIEW -d“http://www.example.com/urlTest”

  • 通过Google应用导航。您应该能够将www.example.com/urlTest放在搜索栏中,并显示消歧窗口。选择导航codelab