I try to select a date (today) in a MultiDatePicker programmatically via a Button. The selection works as expected and the onChange modifier will be called and the day today is marked as selected in the Picker. But when I try to deselect the date directly in the MultiDatePicker, the date is not marked anymore but the onChange modifier will not get called. If you tap on another date in the MultiDatePicker now, both dates, the other date and the date today are marked as selected.
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()
}
}
Am I doing something wrong or is it just not possible to select a date in the MultiDatePicker programmatically?
Thank You!
2
Answers
For purposes of this discussion, Today means December 17, 2022
The issue is that
Date.now
is not equal to TodayI’m in US East Coast Time Zone… if I add a button to
print(Date.now)
and tap it, I see this in the debug console:if I tap it again 4-seconds later, I see this:
Those two dates are not equal.
So, let’s find out what the
MultiDatePicker
is using for it’sselection
.Change your
MultiDatePicker
to this:If I run the app and select Dec 14, 19 and 8, I see this:
Now, I de-select the 19th, and I see this:
The 19th was correctly removed from the
Set
.Now, I tap your "Select today" button, and I see this:
As we can see, these two lines:
Insert a
DateComponents
object with a lot more detail.If I tap "Select today" again, I get this:
Now
selectedDates
contains two "today dates" … 2-minutes and 28-seconds apart.When I tap the 17th on the calendar, there is no matching date in that
set
to remove… so when the calendar refreshes (such as when I select another date), the 17th still shows as selected.So, let’s change the programmatically inserted
DateComponents
to match the calendar’s data:Now when we tap
17
on the calendar it will be de-selected and the matching objectselectedDates
will be removed.Here’s how I modified your code to debug:
it looks like
MultiDatePicker
is saving additional components.Use this to set the today components: