I am new in SwiftUI. I am trying to implementing MultiDatePicker where user can select minimum data and maximum date in calendar. Once a dates are selected, all the dates which are comes in selected date range should be automatically selected.
Here is my code.
import SwiftUI
struct count: View {
@Environment(\.calendar) var calendar
@State private var dates: Set<DateComponents> = []
let datePickerComponents: Set<Calendar.Component> = [.calendar, .era, .year, .month, .day]
var datesBinding: Binding<Set<DateComponents>> {
Binding {
dates
} set: { newValue in
if newValue.isEmpty {
dates = newValue
} else if newValue.count > dates.count {
if newValue.count == 1 {
dates = newValue
} else if newValue.count == 2 {
dates = filledRange(selectedDates: newValue)
} else if let firstMissingDate = newValue.subtracting(dates).first {
dates = [firstMissingDate]
} else {
dates = []
}
} else if let firstMissingDate = dates.subtracting(newValue).first {
dates = [firstMissingDate]
} else {
dates = []
}
}
}
var body: some View {
VStack(spacing: 50){
MultiDatePicker("Select dates", selection: datesBinding)
.frame(height: 300)
}
.padding()
}
private func filledRange(selectedDates: Set<DateComponents>) -> Set<DateComponents> {
let allDates = selectedDates.compactMap { calendar.date(from: $0) }
let sortedDates = allDates.sorted()
var datesToAdd = [DateComponents]()
if let first = sortedDates.first, let last = sortedDates.last {
var date = first
while date < last {
if let nextDate = calendar.date(byAdding: .day, value: 1, to: date) {
if !sortedDates.contains(nextDate) {
let dateComponents = calendar.dateComponents(datePickerComponents, from: nextDate)
datesToAdd.append(dateComponents)
}
date = nextDate
} else {
break
}
}
}
return selectedDates.union(datesToAdd)
}
}
#Preview {
count()
}
My problem : It is working like a charm when user select the range within the 4 months but if user select the maximum date after the 4th month then it will not work. i.e. if user select from 1st January to 10th January it is working, it is working even user select from 1st January to any date till April. Once user select the to date that beyond the May and so then it is not working.
Attaching GIF file here for better understanding.
I was able to reproduce the problem when running on an iPhone 15 simulator with iOS 17.5.
I then tried a test by taking out all the setter logic in your computed binding, reducing it to:
Binding {
dates
} set: { newValue in
dates = newValue
}
This leaves the MultiDatePicker
working in the native, default way.
I then selected every date manually, from today onwards. Today is 06 Jan. When you get to May, the date picker behaves unreliably and starts dropping dates.
My conclusion is that MultiDatePicker
is buggy on iOS 17 and cannot handle a large set of dates reliably.
The good news is, it seems to work on iOS 18.
To resolve your problem, I think you need to consider using a custom date selector that is better suited to supporting a range of dates. Ideally, you should only need to supply the start date and end date and not have to fill all the dates in-between.