news 2026/5/20 16:38:37

Jetpack Compose Navigation 全面使用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Jetpack Compose Navigation 全面使用指南

🧭 一、为什么需要 Navigation?

在 Compose 中,你不再用Activity 跳转,而是用“声明式导航”

  • 页面 =Composable 函数
  • 跳转 =改变当前“目的地”(Destination)
  • 返回 =从导航栈弹出

Jetpack Compose Navigation 提供了一套统一、安全、带生命周期管理的导航方案。

🛠 二、快速上手:3 步实现页面跳转

第 1 步:添加依赖(build.gradle)

implementation"androidx.navigation:navigation-compose:2.8.0"

第 2 步:定义你的页面(Composable)

@ComposablefunHomeScreen(onNavigateToProfile:()->Unit){Column{Text("首页")Button(onClick=onNavigateToProfile){Text("去个人页")}}}@ComposablefunProfileScreen(){Text("个人中心")}

第 3 步:搭建导航图(NavGraph)

@ComposablefunMyApp(){valnavController=rememberNavController()NavHost(navController=navController,startDestination="home"){composable("home"){HomeScreen{navController.navigate("profile")}}composable("profile"){ProfileScreen()}}}

✅ 效果:点击按钮 → 跳转到个人页!

✅ 返回键自动生效(因为 NavHost 管理了返回栈)

🔑 三、核心概念解析

概念说明
NavController导航控制器,负责跳转、返回等操作
NavHost导航容器,定义所有页面(目的地)
composable(route)声明一个页面,route 是唯一标识(如 “profile”)
导航栈(Back Stack)记录用户访问路径,支持返回

💡 记住:

  • rememberNavController():在 Composable 中获取 NavController
  • 每个 composable 块对应一个页面

📦 四、页面传参(Arguments)

场景:从首页跳转到用户详情页,传userId

✅ 步骤 1:定义带参数的 route
// 使用 {id} 占位符composable("user/{userId}"){backStackEntry->// 从 backStackEntry 获取参数valuserId=backStackEntry.arguments?.getString("userId")?:"unknown"UserDetailScreen(userId=userId)}
✅ 步骤 2:跳转时传值
// 在 HomeScreen 中Button(onClick={navController.navigate("user/123")})

✅ 进阶:类型安全传参(推荐!)

使用 Navigation Safe Args(Compose 版) 或 自定义解析。

方法 A:手动解析(简单场景)
composable("user/{userId}"){entry->valuserId=entry.pathSegments[1]// ["user", "123"]UserDetailScreen(userId)}
方法 B:使用 navArgs + Parcelable(更安全)
// 定义数据类@ParcelizedataclassUserArgs(valid:String,valname:String):Parcelable// 跳转valargs=UserArgs("123","Alice")navController.navigate("user?args=${Uri.encode(args.toString())}")// 不推荐,复杂// 更推荐:直接拼接基础类型navController.navigate("user/${userId}")

📌 官方建议:

对于简单参数(String/Int),直接用 {param};

复杂对象优先通过 ViewModel 共享,而非导航传参。

🔙 五、返回并传递结果(类似 startActivityForResult)

Compose Navigation 原生不支持返回结果,但我们可以用 ViewModel + Shared State 实现。
✅ 推荐方案:共享 ViewModel

// 共享 ViewModel@HiltViewModelclassSharedViewModel@Injectconstructor():ViewModel(){privateval_selectedItem=MutableStateFlow<String?>("")valselectedItem=_selectedItem.asStateFlow()funselectItem(item:String){_selectedItem.value=item}}// 主页@ComposablefunSelectHomeScreen(viewModel:SharedViewModel,onNavigateToSelectItem:()->Unit){valselectedItembyviewModel.selectedItem.collectAsState()Column{Text("选中数据:${selectedItem}")Button(onClick=onNavigateToSelectItem){Text("选项选择")}}}// 选择页@ComposablefunPickerScreen(viewModel:SharedViewModel,onNavigateBackHome:()->Unit){Column{Button(onClick={viewModel.selectItem("选项A")onNavigateBackHome()}){Text("选项A")}}}

✅ 优点:解耦、可测试、支持跨多层返回

💡 注:HiltViewModel 如果没有这个注解,需要引入依赖:

implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.3.0")

🌐 六、深度链接(Deep Link)

让外部链接(如网页、通知)直接打开 App 内页面。

步骤 1:在 composable 中注册 deep link

composable("profile",deepLinks=listOf(navDeepLink{uriPattern="myapp://profile"})){ProfileScreen()}

步骤 2:在 AndroidManifest.xml 中声明

<activityandroid:name=".MainActivity"><intent-filter><actionandroid:name="android.intent.action.VIEW"/><categoryandroid:name="android.intent.category.DEFAULT"/><categoryandroid:name="android.intent.category.BROWSABLE"/><dataandroid:scheme="myapp"android:host="profile"/></intent-filter></activity>

效果:点击 myapp://profile → 直接打开个人页!

🧪 七、测试导航

使用 createAndroidComposeRule + navigate() 模拟跳转。

@TestfuntestNavigateToProfile(){composeTestRule.setContent{MyApp()}// 点击按钮composeTestRule.onNodeWithText("去个人页").performClick()// 验证是否显示个人页内容composeTestRule.onNodeWithText("个人中心").assertExists()}

⚙️ 八、高级技巧

1. 嵌套路由(Nested Graph)

//TODO main是外层的路由路径,home是嵌套内开始展示UI的路由路径navigation(startDestination="home",route="main"){composable("home"){HomeScreen()}composable("settings"){SettingsScreen()}}composable("login"){LoginScreen()}

2. 自定义过渡动画

composable("profile",enterTransition={slideInHorizontally(initialOffsetX={it})},exitTransition={slideOutHorizontally(targetOffsetX={-it})}){...}
3. 拦截返回键
BackHandler(enabled=canExit){navController.popBackStack()}

✅ 十、最佳实践总结

  • 导航图集中管理:所有 composable 定义在一个地方(如 NavGraph.kt)
  • 参数尽量简单:用 ID 代替完整对象
  • 返回结果用共享状态:避免 hack 式回调
  • 深度链接提前规划:方便运营和分享
  • 动画适度使用:提升体验但别过度

🎯 结语

Jetpack Compose Navigation 不只是“页面跳转”,而是一套完整的页面生命周期管理方案。

它帮你处理了:

  • 返回栈
  • 状态保存(配合 rememberSaveable)
  • 深度链接
  • 动画过渡
  • 测试支持

只要掌握NavController+NavHost+composable三件套,你就能构建任意复杂的 App 导航结构!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 5:21:33

终极数据科学IDE:Positron完整使用指南

终极数据科学IDE&#xff1a;Positron完整使用指南 【免费下载链接】positron Positron, a next-generation data science IDE 项目地址: https://gitcode.com/gh_mirrors/po/positron Positron是Posit PBC开发的新一代数据科学集成开发环境&#xff0c;专为多语言数据科…

作者头像 李华
网站建设 2026/5/11 5:58:23

MIFARE Classic Tool技术指南:Android平台NFC标签操作解决方案

MIFARE Classic Tool技术指南&#xff1a;Android平台NFC标签操作解决方案 【免费下载链接】MifareClassicTool An Android NFC app for reading, writing, analyzing, etc. MIFARE Classic RFID tags. 项目地址: https://gitcode.com/gh_mirrors/mi/MifareClassicTool …

作者头像 李华
网站建设 2026/5/11 13:19:31

牙科就诊管理系统(11460)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华
网站建设 2026/5/19 21:54:55

用Realtek数字输出打造智能家居音频中心

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个家庭音频分发系统原型&#xff1a;1.支持DLNA/AirPlay 2.多区域同步播放 3.音频流转换(SPDIF转网络) 4.简单的Web控制界面 5.定时播放功能。使用PythonFlask实现&#xff0…

作者头像 李华
网站建设 2026/5/20 0:36:17

用WebRTC快速验证你的社交产品创意

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个社交产品原型方案&#xff0c;使用WebRTC实现核心功能。要求&#xff1a;1. 基于兴趣匹配的随机视频聊天功能&#xff1b;2. 简单的用户个人资料系统&#xff1b;3. 聊天记…

作者头像 李华
网站建设 2026/5/13 16:49:34

蜘蛛池有什么用?一篇讲透收录、爬取、排名的关联

很多做 SEO 的朋友都疑惑&#xff1a;蜘蛛池到底有什么用&#xff1f;它和搜索引擎的爬取、收录、排名之间到底是什么关系&#xff1f;其实蜘蛛池的核心价值&#xff0c;就是串联起 “爬取 - 收录 - 排名” 的优化链路&#xff0c;成为网站从 “被发现” 到 “获曝光先明确三者…

作者头像 李华