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

使用ViewModel向LazyRow添加条目遇阻,求解决方案

问题场景

点击卡片弹出日期选择框,用户选完日期点击确认后,将新条目添加到LazyRow中。尝试用事件处理器结合ViewModel添加并监听列表变化,但未成功实现。以下是代码及问题点:

ViewModel.kt

@HiltViewModel
class HabitsViewModel @Inject constructor(
    private val habitUseCases: HabitUseCases,
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    private val remindersState = MutableStateFlow(ReminderListState())
    //用于监听列表状态
    fun consumableState() = remindersState.asStateFlow()
    
    fun onEvent(event: HabitsEvent) {
        when(event) {
            is HabitsEvent.AddItem -> {
                val currentState = remindersState.value
                val items = currentState.reminders.toMutableList().apply {
                    //此处困惑:如何获取用户选中的当前日期值
                    add()
                }.toList()

                remindersState.value = remindersState.value.copy(
                    reminders = items
                )
            }
        }
    }
}

事件类与列表数据类

sealed class HabitsEvent() {
    object AddItem: HabitsEvent()
}

data class ReminderListState(val reminders : List<String> = emptyList())

LazyRow 组件

@Composable
fun RemindMeComponent(
    modifier : Modifier = Modifier,
    onClick : () -> Unit,
    habitsViewModel: HabitsViewModel = viewModel()
) {
    val reminderState = habitsViewModel.consumableState().collectAsState()

    Row(
        modifier = modifier
    ) {
        RemindMeCard(
            onClick = onClick,
            imageVector = Icons.Default.Add
        )
        Spacer(
            modifier = Modifier.width(8.dp)
        )
        LazyRow() {
            items(reminderState.value.reminders) {
                reminderState.value.reminders.forEach { date ->
                    Column {
                        RemindMeCard(
                            onClick = { /*TODO*/ },
                            imageVector = Icons.Default.RingVolume,
                        )
                        Text(
                            text = date,
                            fontSize = 12.sp
                        )
                    }
                }
            }
        }
    }
}

MaterialDialog 确认按钮

//此处应实现向列表添加新条目
positiveButton(
    text = "Ok",
    onClick = {
        habitsViewModel.onEvent(
            HabitsEvent.AddItem
        )
    }
)

预期效果

预期效果

核心问题

  1. 如何在ViewModel的AddItem事件中获取用户选中的日期值?
  2. LazyRow中重复遍历的逻辑该如何修正?
  3. 为何ViewModel更新列表状态后LazyRow未刷新?

解决方案

1. 传递选中的日期到ViewModel

修改HabitsEvent的AddItem为带参数的数据类,将用户选中的日期作为参数传递:

sealed class HabitsEvent {
    data class AddItem(val selectedDate: String) : HabitsEvent()
}

在MaterialDialog确认按钮点击时,获取并格式化用户选中的日期(以MaterialDatePicker为例),再传递给ViewModel:

// 示例:获取并格式化选中日期
val selectedDate = picker.selectedDate?.let {
    SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(it))
} ?: ""

positiveButton(
    text = "Ok",
    onClick = {
        habitsViewModel.onEvent(HabitsEvent.AddItem(selectedDate))
    }
)

ViewModel中直接使用事件参数添加日期:

fun onEvent(event: HabitsEvent) {
    when(event) {
        is HabitsEvent.AddItem -> {
            val newItems = remindersState.value.reminders + event.selectedDate
            remindersState.value = remindersState.value.copy(reminders = newItems)
        }
    }
}

2. 修正LazyRow的重复遍历逻辑

LazyRow的items函数已在遍历列表,内部无需再调用forEach,否则会导致每个列表项重复渲染整个列表。修改后:

LazyRow() {
    items(reminderState.value.reminders) { date ->
        Column {
            RemindMeCard(
                onClick = { /*TODO*/ },
                imageVector = Icons.Default.RingVolume,
            )
            Text(
                text = date,
                fontSize = 12.sp
            )
        }
    }
}

3. 解决LazyRow未刷新的问题

  • 保证列表更新的不可变性:必须创建新的列表实例(不能修改原列表),上述方案中currentItems + event.selectedDate会生成新列表,满足StateFlow的更新要求。
  • 使用生命周期感知的状态收集:替换collectAsState()为collectAsStateWithLifecycle(),它会跟随Compose生命周期自动管理收集,避免无效更新:
// 需依赖 androidx.lifecycle:lifecycle-runtime-compose
val reminderState = habitsViewModel.consumableState().collectAsStateWithLifecycle()
  • 确认ViewModel实例一致:确保弹窗和RemindMeComponent使用的是同一个HabitsViewModel实例,比如二者属于同一个Activity或导航图的ViewModelStoreOwner。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:20:33