如何在DatePicker中选择用户无法选择的某些日子?

时间:2021-02-19 22:33:04

标签: swiftui datepicker

假设我有一个简单的 DatePicker 视图:

struct ContentView: View {
  @State private var date = Date()

  var body: some View {
    DatePicker("Date", selection: $date)
        .datePickerStyle(GraphicalDatePickerStyle())
  }
}

我怎样才能让用户在星期日或节假日都不能点击?

1 个答案:

答案 0 :(得分:0)

好的,所以这不是一件容易的事。经过大量调查,我最终使用了 WenchaoD's FSCalendar

这花了很多工作,我在日历中添加了我最初想要的其他内容,但这就是最终结果:

struct MyCalendar: UIViewRepresentable {

typealias UIViewType = FSCalendar

@Binding var selectedDate: Date
@Binding var listOfAvailableTimes: [String]
@Binding var appointmentType: String
@Binding var currentPage: Date

@ObservedObject var eventsManager = EventsManager()

var calendar = FSCalendar()

var today: Date {
    return Date()
}

func makeCoordinator() -> MyCalendar.Coordinator {
    Coordinator(self)
}
func makeUIView(context: Context) -> FSCalendar {
    
    eventsManager.fetchHolidays(year: 2021)
    
    calendar.delegate = context.coordinator
    calendar.dataSource = context.coordinator
    
    calendar.scrollDirection = .horizontal
    calendar.scope = .month
    calendar.locale = Locale(identifier: "es")
    
    calendar.appearance.titleFont = UIFont.systemFont(ofSize: 17)
    calendar.appearance.headerTitleFont = UIFont.boldSystemFont(ofSize: 18)
    calendar.appearance.weekdayFont = UIFont.boldSystemFont(ofSize: 16)
    
    calendar.appearance.todayColor = .none
    calendar.appearance.titleTodayColor = .black
    calendar.appearance.weekdayTextColor = .systemGray
    calendar.appearance.headerTitleColor = .black
    
    calendar.placeholderType = .none
    
    calendar.appearance.headerMinimumDissolvedAlpha = 0
    
    return calendar
}

func updateUIView(_ uiView: FSCalendar, context: Context) {
    uiView.setCurrentPage(currentPage, animated: true)
    calendar.reloadData()
}

class Coordinator: NSObject, FSCalendarDelegateAppearance, FSCalendarDataSource, FSCalendarDelegate {
    
    fileprivate let gregorian: Calendar = Calendar(identifier: .gregorian)
    
    var parent: MyCalendar
    
    init(_ calendar: MyCalendar) {
        self.parent = calendar
    }
    
    var formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/yyyy"
        return formatter
    }()
    
//STARTING HERE IS WHERE YOU CAN SEE THE CODE TO INDICATE 
//WHICH DAYS SHOULD NOT BE SELECTED. I GOT THE LIST OF HOLIDAYS 
//FROM AN API. LET ME KNOW IF YOU NEED HELP WITH THIS OTHER PART.

    func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
        
        // IF DATE IS A HOLIDAY, IT SHOULD APPEAR RED
        let listOfHolidays = self.parent.eventsManager.holidays
        
        for holiday in listOfHolidays {
            guard let excludedDate = formatter.date(from: holiday) else { return nil }
            
            if date.compare(excludedDate) == .orderedSame {
                return .red
            }
        }
        
        // IF DATE IS A SUNDAY, IT SHOULD APPEAR RED
        if [1].contains((self.gregorian.component(.weekday, from: date))) {
            return .red
        }
        return nil
    }
    
    func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
        
        var stringSelectedDate: String {

            let year = Calendar.current.component(.year, from: date)
            let month = Calendar.current.component(.month, from: date)
            let day = Calendar.current.component(.day, from: date)

            let stringDate = String(format: "%04d%02d%02d", year, month, day)

            return stringDate
        }
        
        self.parent.eventsManager.searchAppointment(day: stringSelectedDate, appointmentType: self.parent.appointmentType) { (appointment) in
            self.parent.listOfAvailableTimes = appointment?.times ?? [""]
        }
        self.parent.selectedDate = date
        print("Date Selected = \(formatter.string(from: date))")
    }
    
    
    func minimumDate(for calendar: FSCalendar) -> Date {
        return Date()
    }
    
    func maximumDate(for calendar: FSCalendar) -> Date {
        return Date().addingTimeInterval((60 * 60 * 24) * 365)
    }
    
    func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
        
        let listOfHolidays = self.parent.eventsManager.holidays
        
        for holiday in listOfHolidays {

            // IF DATE IS A HOLIDAY, IT SHOULD NOT BE CLICKABLE
            guard let excludedDate = formatter.date(from: holiday) else { return true }
            if date.compare(excludedDate) == .orderedSame {
                return false
            }
        }
        // IF DATE IS A SUNDAY, IT SHOULD NOT BE CLICKABLE
        if [1].contains((self.gregorian.component(.weekday, from: date))) {
            return false
        }
        return true
    }
  }
}

所以在 ContentView 中,我没有使用 DatePicker,而是使用了 MyCalendar

相关问题