You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 03:32:50