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引用,始终持有旧数据。
修复步骤
- 更新
pointerInput的key参数:将pointerInput(Unit)改为pointerInput(sortedItem, taskItem.id),让sortedItem或任务ID变化时,重新创建pointerInput作用域,捕获最新的sortedItem数据。 - 简化
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
相关产品推荐
相关产品推荐

