设计导航图

Navigation 组件使用导航图管理应用导航。导航图是一种数据结构,包含应用内的每个目的地以及这些目的地之间的连接。

目标类型

有三种常规类型的目标:托管、对话框和 activity。下表概述了这三种目的地类型及其用途。

类型

说明

用例

托管

填充整个导航宿主。也就是说,托管目的地的大小与导航宿主的大小相同,之前的目的地不会显示。

主屏幕和详情页面。

对话框

显示叠加界面组件。此界面与导航宿主的位置或大小无关。之前的目的地会显示在目的地下方。

提醒、选择、表单。

活动

表示应用中的独特屏幕或功能。

充当导航图的退出点,启动与 Navigation 组件分开管理的新 Android activity。

在现代 Android 开发中,应用由一个 activity 组成。因此,当与第三方 activity 互动或作为迁移过程的一部分时,最适合使用 activity 目的地。

本文档包含托管目的地的示例,这些目的地是最常用和最基本的目的地。如需了解其他目的地,请参阅以下指南:

框架

虽然相同的常规工作流适用于所有情况,但导航宿主和导航图的创建方式取决于您使用的界面框架。

  • Compose:使用 NavHost 可组合项。使用 Kotlin DSL 为其创建 NavGraph。您可以通过以下两种方式创建图表:
    • 作为 NavHost 的一部分:在添加 NavHost 的过程中直接构建导航图。
    • 以编程方式:使用 NavController.createGraph() 方法创建 NavGraph 并将其直接传递给 NavHost
  • fragment:将 fragment 与视图界面框架搭配使用时,请使用 NavHostFragment 作为宿主。您可以通过多种方式创建导航图:
    • 以编程方式:使用 Kotlin DSL 创建 NavGraph 并将其直接应用于 NavHostFragment
      • Kotlin DSL 用于 fragment 和 Compose 的 createGraph() 函数是相同的。
    • XML:直接使用 XML 编写导航宿主和图表。
    • Android Studio 编辑器:使用 Android Studio 中的 GUI 编辑器创建图表并将其调整为 XML 资源文件。

Compose

在 Compose 中,使用 NavHost 可组合项创建导航图。请参考以下示例:

val navController = rememberNavController()

NavHost(navController = navController, startDestination = "profile") {
    composable("profile") { Profile( /* ... */ ) }
    composable("friendslist") { FriendsList( /* ... */ ) }
    // Add more destinations similarly.
}
  1. 调用 NavHost 可组合项会传递 NavController 和与起始目的地对应的 route 字符串。
  2. 传递给 NavHost 的 lambda 最终会调用 NavController.creatGraph() 并返回 NavGraph
  3. NavGraphBuilder.composable() 的调用会将目的地添加到生成的 NavGraph 中。
  4. 在本例中,目的地是 ProfileFriendsList 可组合项。路由字符串 "profile""friendslist" 成为标识两个目的地的键。

为了更好地了解创建 NavGraph 的 lambda,请考虑用与前面的代码段相同的方式构建相同的图,您可以使用 NavController.createGraph() 单独创建 NavGraph 并将其直接传递给 NavHost

val navGraph by remember(navController) {
  navController.createGraph(startDestination = "profile") {
    composable("profile") { Profile() }
    composable("friendslist") { FriendsList() }
  }
}
NavHost(navController, navGraph)

最小示例

NavControllerNavHost 协同工作的最小但完整示例:

// Define the Profile composable.
@Composable
fun Profile(onNavigateToFriendsList: () -> Unit) {
  Text("Profile")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsList composable.
@Composable
fun FriendsList(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = "profile") {
    composable("profile") { Profile(onNavigateToFriendsList = { navController.navigate("friendslist") }) }
    composable("friendslist") { FriendsList(onNavigateToProfile = { navController.navigate("profile") }) }
  }
}

如代码段所示,向 NavHost 公开事件,而不是将 NavController 传递给可组合项。也就是说,可组合项应具有一个类型为 () -> Unit 的参数,NavHost 可以为该参数传递一个调用 NavController.navigate() 的 lambda。

Fragment

如前几部分所述,在使用 fragment 时,您可以选择使用 Kotlin DSL、XML 或 Android Studio 编辑器以编程方式创建导航图。

以下部分详细介绍了这些不同的方法。

以编程方式

Kotlin DSL 提供了一种以编程方式创建包含 fragment 的导航图的方法。从许多方面来说,这比使用 XML 资源文件更简洁且更时尚。

请考虑以下示例,它实现了双屏导航图。

首先,您需要创建 NavHostFragment,它不得包含 app:navGraph 元素:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

接下来,将 NavHostFragmentid 传递给 NavController.findNavController()。这会将 NavController 与 NavHostFragment 相关联。

随后,对 NavController.createGraph() 的调用会将该图关联到 NavController,继而关联到 NavHostFragment

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = "profile"
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment>("profile") {
        label = "Profile"
    }

    fragment<FriendsListFragment>("friendsList") {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

以这种方式使用 DSL 与上文关于 Compose 的部分中介绍的工作流非常相似。例如,在此处和此处,NavController.createGraph() 函数都会生成 NavGraph。同样,虽然 NavGraphBuilder.composable() 会向图表添加可组合目的地,但此处的 NavGraphBuilder.fragment() 会添加 fragment 目的地。

如需详细了解如何使用 Kotlin DSL,请参阅使用 NavGraphBuilder DSL 构建图表

XML

您可以直接自行编写 XML。以下示例是上一部分中的双屏示例的镜像,效果相同。

首先,创建一个 NavHostFragment。它充当包含实际导航图的导航宿主。

NavHostFragment 的最低实现:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

NavHostFragment 包含 app:navGraph 属性。使用此属性可将导航图连接到导航宿主。以下示例展示了如何实现该图:

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

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

您可以使用操作来定义不同目的地之间的连接。在此示例中,profile fragment 包含一项导航到 friendslist 的操作。如需了解详情,请参阅使用导航操作和 fragment

编辑者

您可以使用 Android Studio 中的 Navigation Editor 管理应用的导航图。这本质上是一个可用于创建和修改 NavigationFragment XML 的 GUI,如上一部分所示。

如需了解详情,请参阅导航编辑器

嵌套图

您还可以使用嵌套图表。这涉及使用图作为导航目的地。如需了解详情,请参阅嵌套图

延伸阅读

如需了解更多核心导航概念,请参阅以下指南:

  • 概览:请务必阅读 Navigation 组件的一般概览。
  • activity 目的地:有关如何实现将用户转到 activity 的目的地的示例。
  • 对话框目的地:有关如何创建用于将用户转到对话框的目的地的示例。
  • 导航到目的地:有关如何从一个目的地导航到另一个目的地的详细指南。
  • 嵌套图:有关如何将一个导航图嵌套在另一个导航图中的深入指南。