Jetpack Compose中LazyVerticalGrid内Card点击导航错误解决
解决Jetpack Compose LazyVerticalGrid中Card跳转的导航错误
错误原因
你在Card的onClick回调里调用NavHost导致报错,核心问题有两点:
NavHost是带@Composable注解的函数,只能在同样标注@Composable的函数上下文里调用,而onClick是普通函数类型的回调,不属于Composable上下文范畴- 每个
Card内部单独创建rememberNavController()是错误设计,NavController应该在整个导航结构的顶层(比如App根Composable)创建后向下传递,而非每个子组件重复生成
正确实现方式
1. 搭建顶层导航结构
首先在App的根节点设置NavHost,统一管理所有页面路由,比如在MainActivity的setContent中:
@Composable fun MainApp() { val navController = rememberNavController() NavHost(navController = navController, startDestination = "grid") { composable("grid") { GridView(navController = navController) // 将NavController传递给网格组件 } composable("greetings") { GreetingsScreen() } // Greetings对应的目标页面 composable("fruits") { FruitsScreen() } // Fruits对应的目标页面 // 按需求添加其他页面的路由配置 } }
2. 修改GridView组件逻辑
调整gridview函数,接收外部传递的NavController,在Card的onClick中调用navController.navigate()完成跳转,同时优化列表初始化逻辑:
@OptIn(ExperimentalMaterialApi::class) @Composable fun GridView(navController: NavController) { // 简化列表初始化写法 val languageList = listOf( LanguageModel("Greetings", R.drawable.wave), LanguageModel("Fruits", R.drawable.fruits), LanguageModel("Flower", R.drawable.sakura), LanguageModel("Numbers", R.drawable.numbers), LanguageModel("Family", R.drawable.family), LanguageModel("Months", R.drawable.calendar), LanguageModel("Sports", R.drawable.sports), LanguageModel("Time", R.drawable.clock), LanguageModel("Food", R.drawable.food), LanguageModel("Days", R.drawable.day) ) LazyVerticalGrid(columns = GridCells.Fixed(2), modifier = Modifier.padding(10.dp)) { items(languageList) { item -> // 直接遍历列表元素,代码更直观 Card( shape = RoundedCornerShape(10.dp), onClick = { // 用when替代if-else,逻辑更清晰 val targetRoute = when (item.english) { "Greetings" -> "greetings" "Fruits" -> "fruits" "Flower" -> "flower" "Numbers" -> "numbers" "Family" -> "family" "Months" -> "months" "Sports" -> "sports" "Time" -> "time" "Food" -> "food" "Days" -> "days" else -> "" } if (targetRoute.isNotEmpty()) { navController.navigate(targetRoute) } }, modifier = Modifier.padding(8.dp), elevation = 6.dp ) { Column( modifier = Modifier .fillMaxSize() .padding(5.dp) .background(Color(216, 191, 216)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Image( painter = painterResource(id = item.languageImage), contentDescription = "Learn ${item.english}", modifier = Modifier .size(60.dp) .padding(5.dp) ) Spacer(modifier = Modifier.height(9.dp)) Text( text = item.english, modifier = Modifier.padding(4.dp), color = Color.Black, fontWeight = FontWeight.Bold ) } } } } }
3. 优化建议
- 路由名称要和
NavHost中composable配置的完全一致,否则无法匹配跳转 - 如果需要传递页面参数,可以在路由中添加占位符,比如
composable("greetings/{itemId}"),跳转时用navController.navigate("greetings/1001")传递参数 - 可以给
LanguageModel新增route字段,直接存储对应页面的路由字符串,进一步简化onClick中的匹配逻辑:data class LanguageModel(val english: String, val languageImage: Int, val route: String) // 初始化时直接指定路由 LanguageModel("Greetings", R.drawable.wave, "greetings") // 跳转时直接调用 navController.navigate(item.route)
内容的提问来源于stack exchange,提问作者Tejas Khartude
相关产品推荐
相关产品推荐

