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

通过代码设置MultiDatePicker选中项后,onChange未触发的问题

MultiDatePicker 编程选中后手动取消无响应及异常选中问题

问题现象

  • 点击按钮编程选中今日日期:MultiDatePicker正确标记日期,onChange触发,计数器正常递增。
  • 在选择器中手动取消今日日期的选中:标记消失,但onChange未触发,计数器无变化。
  • 此时点击选择器内其他日期:新日期与今日日期会同时被标记,onChange触发一次。

复现代码

import SwiftUI

struct ContentView: View {

    @Environment(\.calendar) private var calendar

    @State private var selectedDates: Set<DateComponents> = []

    @State private var onChangeCounter = 0
    
    var body: some View {
        VStack {
            MultiDatePicker("Select dates", selection: $selectedDates)
                .frame(height: UIScreen.main.bounds.width)
                .onChange(of: selectedDates) { _ in
                    self.onChangeCounter += 1
                }

            Button("Select today") {
                let todayDatecomponents = calendar.dateComponents(in: calendar.timeZone, from: Date.now)
                selectedDates.insert(todayDatecomponents)
            }
            .foregroundColor(.white)
            .frame(minWidth: 150)
            .padding()
            .background(Color.accentColor)
            .cornerRadius(20)

            HStack {
                Text("onChangeCounter")
                Spacer()
                Text(String(onChangeCounter))
            }
            .padding()

            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

iPhone Screenvideo

问题原因

MultiDatePicker处理用户交互时生成的DateComponents仅包含year、month、day三个字段,但通过calendar.dateComponents(in:from:)生成的实例包含了额外字段(如hour、timeZone等)。这导致集合中存在两个逻辑相同但实例不相等的DateComponents:

  1. 编程插入的带完整字段的实例
  2. 选择器内部维护的仅含年月日的实例

手动取消时,选择器仅移除自身维护的实例,集合内仍保留编程插入的实例,因此onChange未触发(集合内容未改变);后续点击其他日期时,选择器会将之前的“幽灵”实例重新加入,造成异常选中。

解决方案

编程插入日期时,仅保留year、month、day三个必要字段,与选择器内部生成的格式保持一致:

Button("Select today") {
    let today = Date.now
    let todayDatecomponents = calendar.dateComponents([.year, .month, .day], from: today)
    selectedDates.insert(todayDatecomponents)
}

修改后验证:

  • 手动取消今日日期时,onChange正常触发,计数器递增
  • 点击其他日期不会出现异常同时选中的情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:50:16