Navigation Compose — 是一个 Jetpack 库,用于在基于 Jetpack Compose 构建的 Android 应用程序中进行声明式导航。与 FragmentManager 或基于 Intent 的导航不同,Navigation Compose 提供了通过 NavController 和 NavHost 管理的统一路由图。根据 Google I/O (2025) 的数据,Navigation Compose 是 Compose 应用程序推荐的导航方式,被超过 70% 的新项目使用。该库支持传递类型化参数、深层链接、过渡动画以及通过 SavedStateHandle 与 ViewModel 集成。
要点
Navigation Compose — 是 Jetpack 套件中的一个库,为 Compose 应用程序提供导航框架。该库基于与 View 系统的 Navigation Component 相同的原理,但适用于 Compose 的声明式特性:使用 composable 函数代替 FragmentTransaction,导航图通过 Kotlin DSL 构建。
Navigation Compose 与经典导航的关键区别 — 没有 FragmentManager。每个屏幕都是一个 composable 函数,在路由匹配时在 NavHost 中渲染。返回栈存储的不是 Fragment,而是包含路由、参数和状态的记录。这简化了架构,并消除了 Fragment 导航特有的生命周期冲突。
根据 Google (2025) 的数据,Navigation Compose 已从 experimental 演进到 stable,并从 2.8.0 版本开始成为 Jetpack 的一部分。该库支持 Material3、Type-Safe Navigation(通过 Kotlin Serialization)、嵌套图和模块化。唯一的限制 — 该库不支持 BottomNavigation 的 multi-back stack(无需手动配置),尽管 Google 正在努力解决这个问题。
Navigation Compose 的架构围绕三个实体构建:NavController(栈管理)、NavHost(图容器)和 NavDestination(带有 composable 的单独路由)。它们之间的交互是声明式的:开发者描述路由和参数,库处理加载、保存和恢复状态。
NavController — Navigation Compose 的核心元素,管理导航栈。通过 rememberNavController() 创建并传递给 NavHost。NavController 存储返回栈、当前入口点,并支持延迟操作(在图初始化后的深层链接)。
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("profile/{userId}") { backStackEntry ->
ProfileScreen(
userId = backStackEntry.arguments?.getString("userId") ?: ""
)
}
}
}
NavController 的主要方法:navigate(route) — 导航到路由,popBackStack() — 返回上一个屏幕,navigateAndClear(route) — 导航并清除栈。NavOptions 定义行为:launchSingleTop 防止重复,popUpTo 清除栈到指定路由,restoreState 恢复先前状态。
要从深层嵌套的 composable 函数访问 NavController,请通过 CompositionLocal 使用 NavHostController。LocalNavController 在 NavHost 内的 ScopedNavController 中提供。在 NavHost 之外(例如,在 BottomNavigation 中),控制器通过参数或 ViewModel 传递。
NavHost — 是一个 composable 容器,将 NavController 与路由图连接起来。每个路由通过 composable(route, arguments, deepLinks) 声明,其中 route 是带有可选 {param} 占位符的路由字符串。当当前路由与 route 匹配时,NavHost 渲染相应的 composable 块。
路由图是分层构建的:可以通过 navigation() 嵌套图来对模块内的路由进行分组。嵌套图有自己的 startDestination,并在公共路由前缀下合并。这允许组织模块化架构,每个功能模块注册自己的子图。
NavHost(
navController = navController,
startDestination = "main"
) {
composable("main") { MainScreen(navController) }
navigation(
route = "auth",
startDestination = "auth/login"
) {
composable("auth/login") { LoginScreen(navController) }
composable("auth/register") { RegisterScreen(navController) }
}
}
NavHost 通过 LocalBackDispatcher 自动处理系统返回按钮(back press)。在 Material3 Scaffold 中,默认获取 NavController 以确保 BottomNavigation 正常工作。NavHost 在路由更改时重新创建 composable,但通过 rememberSaveable 保留输入字段和滚动的状态。
Navigation Compose 支持通过路由参数和 NavType 在屏幕之间传递类型化参数。参数在路由中定义为 {paramName},并通过 composable() 中的 arguments 指定类型。NavType 支持 String、Int、Long、Float、Boolean、Parcelable 和 Serializable。
| 参数类型 | NavType | 路由示例 |
|---|---|---|
| String | NavType.StringType | "profile/{name}" |
| Int | NavType.IntType | "item/{id}" |
| Boolean | NavType.BoolType | "settings?enabled={flag}" |
| Parcelable | NavType.ParcelableType | "details/{item}" |
| Float | NavType.FloatType | "map?lat={lat}&lng={lng}" |
参数从 NavBackStackEntry 通过 arguments?.getType(key) 提取。对于必需参数使用 defaultValue,对于可选参数使用 nullable。Parcelable 支持仅适用于 Kotlin Parcelize 或 kotlinx.parcelize 库。对于复杂对象,建议传递 ID 并通过 ViewModel 加载数据,而不是序列化整个对象。
从 Navigation 2.8.0 版本开始,Type-Safe Navigation 与 Kotlin Serialization 一起可用:路由定义为数据类,参数定义为字段。这用类型化对象替换了字符串路由,并消除了路由名称中的错误。迁移需要 Kotlin Serialization 插件和 navigation-compose-typesafe 依赖项。
@Serializable
/* sealed class Route */
sealed class ProfileRoute(val route: String) {
data object Home : ProfileRoute("home")
data class Profile(val userId: String) : ProfileRoute("profile/{userId}")
}
深层链接 — 一种导航机制,允许通过 URL 或 intent-filter 打开应用程序的特定屏幕。在 Navigation Compose 中,深层链接通过 composable() 中的 deepLinks 参数配置,并在 URI 与模式匹配时自动处理。
深层链接定义为 UriPattern 列表:"https://example.com/profile/{userId}"。URI 中的参数自动映射到路由参数。NavController 在应用程序启动时(通过 intent)和运行期间(通过隐式深层链接)处理深层链接。为了处理待处理的深层链接,在图初始化后在 NavController 中使用 handleDeepLink()。
根据 Google 的建议,深层链接推荐用于:推送通知(Firebase Dynamic Links)、电子邮件验证、内容共享和从 Web 链接导航。对于 Android 12+,使用 Digital Asset Links 验证深层链接的权威性。AndroidManifest.xml 必须包含带有 autoVerify="true" 的 intent-filter,以便无需对话框即可打开链接。
composable(
route = "profile/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType }),
deepLinks = listOf(
navDeepLink { uriPattern = "https://example.com/profile/{userId}" }
)
) { backStackEntry ->
ProfileScreen(userId = backStackEntry.arguments?.getString("userId") ?: "")
}
Navigation Compose 中深层链接的限制:该库不支持延迟的深层链接 — 只有在 NavHost 完全构建图之后,深层链接才会被处理。如果深层链接在图初始化之前到达,则需要通过 intent?.data 延迟并在 LaunchedEffect 中处理。对于 Firebase Dynamic Links,请将 Firebase Dynamic Links SDK 与 Navigation Compose 结合使用。
Navigation Compose 通过 composable() 中的 enterTransition、exitTransition、popEnterTransition 和 popExitTransition 参数支持过渡动画。动画通过 Compose Animation API 实现:fadeIn、slideInHorizontally、expandIn 等。默认情况下,动画是禁用的 — 屏幕立即切换。
典型的动画场景:slideInHorizontally 用于向前导航(屏幕从右侧进入),slideOutHorizontally 用于返回(屏幕向右退出)。对于 BottomNavigation,更常使用无滑动淡入淡出动画。动画通过 NavHost 设置,如果没有指定单独的动画,则应用于所有 composable。
NavHost(
navController = navController,
startDestination = "home",
enterTransition = { slideInHorizontally() + fadeIn() },
exitTransition = { slideOutHorizontally() + fadeOut() },
popEnterTransition = { fadeIn() },
popExitTransition = { slideOutHorizontally() + fadeOut() }
) { /* composable */ }
可以通过直接在 composable() 中传递动画参数来为每个 composable 单独重写动画。重要提示:动画不应与系统返回按钮动画冲突。对于共享元素过渡,需要 accompanist-navigation-animation 库或通过 Modifier.graphicsLayer 的自定义实现。根据 Android Developers (2025) 的数据,80% 的生产应用程序使用水平滑动动画进行标准导航。
常见问题
Navigation Compose 无需 Fragment 即可工作,使用 composable 函数和 Kotlin DSL 构建图。Navigation Component (View) 基于 FragmentManager 和 XML 图。Compose 版本更简单、更快,并且没有 Fragment 生命周期。View 的 Navigation Component 仅适用于混合应用程序。
建议传递对象 ID 并通过 ViewModel 与 SavedStateHandle 加载数据。如果对象很简单 — 通过 kotlinx.parcelize 使用 Parcelable。直接通过参数(Bundle)传递大对象限制在约 1 MB,可能导致 TransactionTooLargeException。
是的,通过 NavHost 内的 navigation(route, startDestination) 函数。嵌套图有自己的 startDestination,并在公共路由前缀下合并。这允许为每个功能模块组织具有隔离图的模块化架构。
NavController 通过 Compose 的 BackHandler 自动处理返回按钮。在按下返回按钮时调用 navController.popBackStack()。对于自定义处理(确认退出),在调用 popBackStack() 之前使用 BackHandler(enabled = condition) { callback }。
目前,Navigation Compose 不支持 Compose Multiplatform。对于跨平台项目的 iOS 部分,请使用 Voyager 或 Decompose。Google 正在开发 KMP 支持,但没有发布日期。对于仅限 Android 的项目,Navigation Compose 是唯一推荐的选项。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。