第 27 课2026.08.12
从列表页打开详情页时,通常需要告诉详情页“打开哪一条数据”。把 id 放进路由后,Android 与 iOS 共用同一种参数格式,编译器也能检查参数类型。
第 27 课:Compose 类型安全路由传参
知识点
使用可序列化的 data class 路由,在 Compose Multiplatform 页面之间传递类型安全参数。
用途
从列表页打开详情页时,通常需要告诉详情页“打开哪一条数据”。把 id 放进路由后,Android 与 iOS 共用同一种参数格式,编译器也能检查参数类型。
核心概念
- 无参数路由适合使用
object,带参数路由使用data class。 - 路由类型必须标记
@Serializable。 - 跳转时传入路由实例,例如
Detail(itemId = 42)。 - 目标页面通过
backStackEntry.toRoute<Detail>()还原参数。 - 路由只传最小标识,如
itemId;完整对象应由详情页根据 ID 从数据层读取。
示例代码
kotlin
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.navigation.toRoute
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable
@Serializable
data object Home
@Serializable
data class Detail(val itemId: Long)
@Composable
fun App() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Home,
) {
composable<Home> {
Button(
onClick = {
navController.navigate(Detail(itemId = 42L))
},
) {
Text("查看第 42 条数据")
}
}
composable<Detail> { backStackEntry ->
val route = backStackEntry.toRoute<Detail>()
Text("当前数据 ID:${route.itemId}")
}
}
}这里若误写成 Detail(itemId = "42"),编译阶段就会报类型错误。
5 分钟练习
新增一个用户详情路由 UserDetail,接收字符串类型的 userId。点击首页按钮时传入 "user-100",并在目标页显示该 ID。
参考答案
kotlin
@Serializable
data class UserDetail(val userId: String)
// 首页按钮
Button(
onClick = {
navController.navigate(UserDetail(userId = "user-100"))
},
) {
Text("查看用户")
}
// NavHost 中的目标页
composable<UserDetail> { backStackEntry ->
val route = backStackEntry.toRoute<UserDetail>()
Text("用户 ID:${route.userId}")
}与上一课的联系
上一课用无参数 Home、Detail 路由完成了页面跳转;今天把 Detail 升级为带 itemId 的路由,让目标页知道应加载哪一条数据。