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

Jetpack Compose中pointerInput内sortedItem数组数据缺失求助

问题描述

sortedItem数组从MainActivity传入TimelineItem组件后,仅在pointerInput作用域内出现数据不完整的问题。比如已有任务“apple”时,添加更早日期的任务“banana”(应排在apple之前),双击“banana”时,pointerInput里打印的sortedItem只显示[apple],但其他作用域(比如LaunchedEffect、组件顶层)的打印都是正确的[banana, apple]。已将双击逻辑提取到handleDoubleTap函数,确认问题仅出在pointerInput内部。

解决方案

问题核心是**pointerInput(Unit)的key参数使用固定值Unit**,导致Compose重组时,pointerInput作用域不会更新内部捕获的sortedItem引用,始终持有旧数据。

修复步骤

  1. 更新pointerInput的key参数:将pointerInput(Unit)改为pointerInput(sortedItem, taskItem.id),让sortedItem或任务ID变化时,重新创建pointerInput作用域,捕获最新的sortedItem数据。
  2. 简化handleDoubleTap参数:直接使用组件顶层的sortedItem,无需额外传入,避免参数捕获旧数据的问题。

修改后的代码

@Composable
fun TimelineItem(
    isLast: Boolean,
    date: String,
    day: String,
    strokeWidth: Dp = 8.dp,
    borderWidth: Dp = 1.dp,
    sortedItem:  List<Pair<String, TaskItem>>,
    taskList: List<Pair<String, TaskItem>>
) {
    val lastTapTime = remember { mutableStateOf(0L) }
    val selectedRingId = remember { mutableStateOf<String?>(null) }
    val context = LocalContext.current

    fun navigateToSheet3Activity(description: String) {
        val intent = Intent(context, com.example.mainscreen.ui.Sheet3Activity::class.java).apply {
            putExtra("TASK_DESCRIPTION", description)
        }
        context.startActivity(intent)
    }

    // 直接使用组件顶层的sortedItem,无需额外传入
    fun handleDoubleTap(taskItem: TaskItem) {
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastTapTime.value < 300) {
            println("sorteditem in handleDoubleTap: $sortedItem")

            val sortedIndex = sortedItem.indexOfFirst { it.second.id == taskItem.id }
            println("sortedIndex: $sortedIndex")

            if (sortedIndex != -1) {
                val fetchedItem = sortedItem[sortedIndex].second
                println("fetchedItem: $fetchedItem")
                navigateToSheet3Activity(fetchedItem.description)
            }
        } else {
            selectedRingId.value = if (selectedRingId.value == taskItem.id) null else taskItem.id
        }
        lastTapTime.value = currentTime
    }

    LaunchedEffect(sortedItem) {
        println("sortedItem in LaunchedEffect: $sortedItem")
    }

    println("sorteditem on timelineitem " + "$sortedItem")
    println("sorteditem[0] " + sortedItem[0])

    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 16.dp)
    ) {
        Spacer(modifier = Modifier.width(20.dp))

        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier.wrapContentSize()
        ) {
            Box(modifier = Modifier.size(120.dp)) {
                taskList.forEachIndexed { index, (_, taskItem) ->
                    val ringSize = 120.dp - (index * 17).dp
                    val isSelected = selectedRingId.value == taskItem.id
                    val ringStrokeWidth = if (isSelected) 12.dp else strokeWidth
                    val ringBorderWidth = if (isSelected) 4.dp else borderWidth

                    PercentageRing(
                        date = if (index == 0) date else "",
                        day = if (index == 0) day else "",
                        currentValue = taskItem.currentValue ?: 0,
                        totalValue = taskItem.totalValue,
                        indicatorColor = taskItem.color,
                        ringColor = Color.Gray,
                        strokeWidth = ringStrokeWidth,
                        borderWidth = ringBorderWidth,
                        progress = Float,
                        modifier = Modifier
                            .size(ringSize)
                            .align(Alignment.Center)
                            .clickable {
                                selectedRingId.value = if (selectedRingId.value == taskItem.id) null else taskItem.id
                            }
                    )
                }
            }

            if (!isLast) {
                Spacer(modifier = Modifier.height(16.dp))
                Box(
                    modifier = Modifier
                        .width(2.dp)
                        .height(40.dp)
                        .background(Color.Black)
                )
            }
        }

        Spacer(modifier = Modifier.width(26.dp))

        Box(
            modifier = Modifier
                .fillMaxHeight()
                .weight(1f)
                .align(Alignment.CenterVertically)
        ) {
            Column(modifier = Modifier.align(Alignment.Center)) {
                if (taskList.isNotEmpty()) {
                    taskList.forEachIndexed { index, (taskDescription, taskItem) ->
                        val topPadding = if (index == 0) 0.dp else 20.dp

                        println("sorteditem on timelineitem 2 " + "$sortedItem")

                        Text(
                            text = "${taskItem.description} - ${taskItem.percentage.toInt()}%",
                            style = TextStyle(
                                fontSize = 18.sp,
                                fontWeight = FontWeight.Bold
                            ),
                            modifier = Modifier
                                .padding(top = topPadding)
                                .align(Alignment.CenterHorizontally)
                                .let { textModifier ->
                                    if (taskItem.notificationsEnabled) {
                                        textModifier
                                            .background(
                                                color = Color.Yellow.copy(alpha = 0.2f),
                                                shape = RoundedCornerShape(8.dp)
                                            )
                                            .padding(horizontal = 8.dp, vertical = 4.dp)
                                    } else {
                                        textModifier
                                    }
                                }
                                // 修改pointerInput的key,加入sortedItem和taskItem.id
                                .pointerInput(sortedItem, taskItem.id) {
                                    detectTapGestures(
                                        onTap = { _ ->
                                            println("Before Tap - sorteditem: $sortedItem")
                                            handleDoubleTap(taskItem)
                                            println("After Tap - sorteditem: $sortedItem")
                                        }
                                    )
                                }
                        )

                        Text(
                            text = "${taskItem.startDate} ~ ${taskItem.endDate}",
                            style = TextStyle(
                                fontSize = 10.sp,
                                fontWeight = FontWeight.Normal
                            ),
                            modifier = Modifier
                                .padding(top = 6.dp)
                                .align(Alignment.CenterHorizontally)
                        )
                    }
                }
            }
        }
    }
}

关键修改说明

  • pointerInput的key参数:从Unit改为sortedItem, taskItem.id,确保sortedItem数据更新或任务项变化时,pointerInput作用域重新初始化,捕获最新的sortedItem引用。
  • 简化handleDoubleTap:移除sortedItem参数,直接使用组件顶层的sortedItem,避免函数参数捕获旧数据的问题。
  • 优化赋值逻辑:将if-else赋值简化为一行代码,提升可读性。

内容的提问来源于stack exchange,提问作者Dora Wang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:45:54