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

Jetpack Compose列表项跳转对应页面异常问题排查

问题:Jetpack Compose列表项导航跳转错误,所有项均打开Screen1

点击列表中的Item 1、Item 2、Item 3均打开Screen1,但预期效果应为Item1打开Screen1、Item2打开Screen2、Item3打开Screen3,以下是实现代码:

Data Item

data class DataItem(val text: String, val imageResId: Int)

列表数据

val dataItems = listOf(
    DataItem("Item 1", R.drawable.concrete),
    DataItem("Item 2", R.drawable.plaster),
    DataItem("Item 3", R.drawable.blocks)
)

Screen 1

@Composable fun Screen1(navController: NavController, dataItem: DataItem) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "Screen 1")
        Spacer(modifier = Modifier.height(16.dp))
        Image(
            painter = painterResource(id = dataItem.imageResId),
            contentDescription = null,
            modifier = Modifier
                .size(200.dp)
                .clip(shape = MaterialTheme.shapes.medium)
                .background(MaterialTheme.colorScheme.primary)
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(text = dataItem.text)
    }
}

Screen 2

@Composable fun Screen2(navController: NavController, dataItem: DataItem) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "Screen 2")
        Spacer(modifier = Modifier.height(16.dp))
        Image(
            painter = painterResource(id = dataItem.imageResId),
            contentDescription = null,
            modifier = Modifier
                .size(200.dp)
                .clip(shape = MaterialTheme.shapes.medium)
                .background(MaterialTheme.colorScheme.primary)
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(text = dataItem.text)
    }
}

Screen 3

@Composable fun Screen3(navController: NavController, dataItem: DataItem) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "Screen 3")
        Spacer(modifier = Modifier.height(16.dp))
        Image(
            painter = painterResource(id = dataItem.imageResId),
            contentDescription = null,
            modifier = Modifier
                .size(200.dp)
                .clip(shape = MaterialTheme.shapes.medium)
                .background(MaterialTheme.colorScheme.primary)
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(text = dataItem.text)
    }
}

数据列表页面

@Composable fun DataList(navController: NavController) {
    LazyColumn {
        items(dataItems) { item ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        navController.navigate("screen1/${dataItems.indexOf(item)}")
                    }
            ) {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painter = painterResource(id = item.imageResId),
                        contentDescription = null,
                        modifier = Modifier
                            .size(64.dp)
                            .clip(shape = MaterialTheme.shapes.medium)
                            .background(MaterialTheme.colorScheme.primary)
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    Text(text = item.text)
                }
            }
        }
    }
}

导航配置

@Composable
fun MyApp() {
val navController = rememberNavController()

NavHost(navController, startDestination = "dataList") {
    composable("dataList") {
        DataList(navController = navController)
    }
    composable(
        route = "screen1/{index}",
        arguments = listOf(navArgument("index") { type = NavType.IntType })
    ) { backStackEntry ->
        val index = backStackEntry.arguments?.getInt("index")
        val dataItem = if (index != null && index < dataItems.size) dataItems[index] else dataItems[0]
        Screen1(navController = navController, dataItem = dataItem)
    }
    composable(
        route = "screen2/{index}",
        arguments = listOf(navArgument("index") { type = NavType.IntType })
    ) { backStackEntry ->
        val index = backStackEntry.arguments?.getInt("index")
        val dataItem = if (index != null && index < dataItems.size) dataItems[index] else dataItems[0]
        Screen2(navController = navController, dataItem = dataItem)
    }
    composable(
        route = "screen3/{index}",
        arguments = listOf(navArgument("index") { type = NavType.IntType })
    ) { backStackEntry ->
        val index = backStackEntry.arguments?.getInt("index")
        val dataItem = if (index != null && index < dataItems.size) dataItems[index] else dataItems[0]
        Screen3(navController = navController, dataItem = dataItem)
    }
}
}

问题定位

  • 核心错误在DataList的点击事件逻辑:所有列表项的导航路径都硬编码为"screen1/${dataItems.indexOf(item)}",无论点击哪个Item,都会跳转到Screen1对应的路由,完全没有根据Item的索引匹配Screen2、Screen3的路由。
  • 额外隐患:使用dataItems.indexOf(item)获取索引,如果列表存在重复的DataItem对象,会返回第一个匹配项的索引,导致跳转逻辑混乱。

解决方案

方案1:根据索引动态匹配目标路由

使用itemsIndexed替代items,直接获取每个Item的索引,然后根据索引拼接对应路由:

@Composable fun DataList(navController: NavController) {
    LazyColumn {
        itemsIndexed(dataItems) { index, item ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        val targetRoute = when(index) {
                            0 -> "screen1/$index"
                            1 -> "screen2/$index"
                            2 -> "screen3/$index"
                            else -> "screen1/$index" // 兜底逻辑
                        }
                        navController.navigate(targetRoute)
                    }
            ) {
                // 原有Row内容保持不变
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painter = painterResource(id = item.imageResId),
                        contentDescription = null,
                        modifier = Modifier
                            .size(64.dp)
                            .clip(shape = MaterialTheme.shapes.medium)
                            .background(MaterialTheme.colorScheme.primary)
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    Text(text = item.text)
                }
            }
        }
    }
}

方案2:优化数据结构,预存目标路由(更易扩展)

修改DataItem增加目标路由字段,后续新增Item时无需修改导航逻辑:

data class DataItem(val text: String, val imageResId: Int, val targetRoute: String)

更新列表数据:

val dataItems = listOf(
    DataItem("Item 1", R.drawable.concrete, "screen1/0"),
    DataItem("Item 2", R.drawable.plaster, "screen2/1"),
    DataItem("Item 3", R.drawable.blocks, "screen3/2")
)

简化DataList的点击事件:

@Composable fun DataList(navController: NavController) {
    LazyColumn {
        items(dataItems) { item ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        navController.navigate(item.targetRoute)
                    }
            ) {
                // 原有Row内容保持不变
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painter = painterResource(id = item.imageResId),
                        contentDescription = null,
                        modifier = Modifier
                            .size(64.dp)
                            .clip(shape = MaterialTheme.shapes.medium)
                            .background(MaterialTheme.colorScheme.primary)
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    Text(text = item.text)
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Harsh Wavikar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:34:50