Navigation 组件使用导航图管理应用导航。导航图是一种数据结构,包含应用内的每个目的地以及这些目的地之间的连接。
目的地类型
有三种常规类型的目的地:托管、对话框和 activity。下表概述了这三种目的地类型及其用途。
类型 |
说明 |
用例 |
---|---|---|
托管 |
填充整个导航宿主。也就是说,托管目的地的大小与导航宿主的大小相同,之前的目的地不会显示。 |
主界面和详情界面。 |
对话框 |
显示叠加界面组件。此界面与导航宿主的位置或大小无关。之前的目的地会显示在该目的地下方。 |
提醒、选择、表单。 |
activity |
表示应用中的独特界面或功能。 |
充当导航图的退出点,启动与 Navigation 组件分开管理的新 Android activity。 在 Modern Android Development 中,应用由 1 个 activity 组成。因此,当与第三方 activity 互动或作为迁移过程的一部分时,最适合使用 activity 目的地。 |
本文档包含托管目的地的示例,这些目的地是最常用和最基本的目的地。如需了解其他目的地,请参阅以下指南:
框架
虽然相同的常规工作流适用于所有情况,但导航宿主和导航图的创建方式取决于您使用的界面框架。
- Compose:使用
NavHost
可组合项。使用以下代码将NavGraph
添加到该函数中: Kotlin DSL。您可以通过以下两种方式创建图表:- 作为 NavHost 的一部分:在添加
NavHost
的过程中直接构建导航图。 - 以编程方式:使用
NavController.createGraph()
方法创建NavGraph
并将其直接传递给NavHost
。
- 作为 NavHost 的一部分:在添加
- fragment:将 fragment 与视图界面框架结合使用时,请使用
NavHostFragment
作为主机。您可以通过多种方式创建导航栏 图表: <ph type="x-smartling-placeholder">- </ph>
- 以编程方式:使用 Kotlin DSL 创建
NavGraph
并 直接在NavHostFragment
上应用。- 与 Kotlin DSL 搭配使用的
createGraph()
函数 fragment 和 Compose 是相同的。
- 与 Kotlin DSL 搭配使用的
- XML:直接使用 XML 编写导航宿主和图表。
- Android Studio 编辑器:使用 Android Studio 中的 GUI 编辑器创建图表并将其调整为 XML 资源文件。
- 以编程方式:使用 Kotlin DSL 创建
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.
}
- 可序列化对象表示两个路由(
Profile
和FriendsList
。 - 调用
NavHost
可组合项会传递NavController
和路线 为起始目的地。 - 传递给
NavHost
的 lambda 最终会调用NavController.createGraph()
并返回NavGraph
。 - 每条路线均作为类型参数提供到
NavGraphBuilder.composable<T>()
,用于将目的地添加到 结果为NavGraph
。 - 传递给
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
。
最小示例
NavController
和 NavHost
搭配使用的完整示例:
@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>
接下来,将 NavHostFragment
的 id
传递给 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 的目的地的示例。
- 对话框目的地:有关如何创建用于将用户转到对话框的目的地的示例。
- 导航到目的地:有关如何从一个目的地导航到另一个目的地的详细指南。
- 嵌套图:有关如何嵌套单个导航的深度指南 另一个图表中