设计导航图

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

目的地类型

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

类型

说明

用例

托管

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

主界面和详情界面。

对话框

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

提醒、选择、表单。

activity

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

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

在 Modern Android Development 中,应用由 1 个 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 中,使用可序列化对象或类定义路线。路线用于描述如何前往目的地,并包含目的地所需的所有信息。

使用 @Serializable 注解可自动为路线类型创建必要的序列化和反序列化方法。此注解由 Kotlin 序列化插件提供。按照这些说明添加此插件

定义路线后,使用 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

为便于更好地了解用来创建 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 可组合项会为自己的 name 实参采用 profile.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 =