设计导航图

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

目的地类型

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

类型

说明

用例

托管

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

主界面和详情界面。

对话框

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

提醒、选择、表单。

activity

表示应用中的独特界面或功能。

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

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

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

框架

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

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

Compose

在 Compose 中,使用可序列化对象或类来定义路线。路线 说明了前往某个目的地的方式,并包含 目标。定义路由后,请使用 NavHost 可组合项来创建导航图。请参考以下示例:

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. 可序列化对象表示两个路由(ProfileFriendsList
  2. 调用 NavHost 可组合项会传递 NavController 和路线 为起始目的地。
  3. 传递给 NavHost 的 lambda 最终会调用 NavController.createGraph() 并返回 NavGraph
  4. 每条路线均作为类型参数提供到 NavGraphBuilder.composable<T>(),用于将目的地添加到 结果为 NavGraph
  5. 传递给 composable 的 lambda 就是 NavHost 为此显示的 lambda 目标。

了解 lambda

为便于更好地了解用来创建 NavGraph 的 lambda,不妨这样假想一下:若要创建上面代码段中的相同图表,您可以另行使用 NavController.createGraph() 创建 NavGraph 并将其直接传递给 NavHost

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

传递参数

如果您需要将数据传递到目的地,请使用 包含参数。例如,Profile 路由是一个具有 name 的数据类 参数。

@Serializable
data class Profile(val name: String)

每当需要向该目的地传递参数时,您都可以创建实例 并将参数传递给类构造函数。

对于可选参数,请使用默认值创建可为 null 的字段。

@Serializable
data class Profile(val nickname: String? = null)

获取路由实例

您可以通过 NavBackStackEntry.toRoute()SavedStateHandle.toRoute()。使用 composable()NavBackStackEntry 可作为参数使用。

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

请注意以下代码段中的以下内容:

  • Profile 路线指定导航中的起始目的地 使用 "John Smith" 作为 name 的参数。
  • 目的地本身是 composable<Profile>{} 代码块。
  • ProfileScreen 可组合项会自行接受 profile.name 的值 name 参数。
  • 因此,值 "John Smith" 会传递给 ProfileScreen

最小示例

NavControllerNavHost 搭配使用的完整示例:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

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

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(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(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

如代码段所示,向 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

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// 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(name = "John Smith")
) {
    // 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 的目的地的示例。
  • 对话框目的地有关如何创建用于将用户转到对话框的目的地的示例。
  • 导航到目的地有关如何从一个目的地导航到另一个目的地的详细指南。
  • 嵌套图:有关如何嵌套单个导航的深度指南 另一个图表中