SwiftUI: how to create custom UIDatePicker

这一生的挚爱 提交于 2020-05-30 08:08:29

问题


I succeeded to create UIDatePicker inside SwifUI, but when I change the date wheel in picker the date value not update, here is my code:

    struct DatePicker: UIViewRepresentable {
    @Binding var date: Date

    func makeUIView(context: Context) -> UIDatePicker {
        let view = UIDatePicker()
        view.datePickerMode = .date
        return view
    }
    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        uiView.date = date
    }
}

Then I call it from the view like this:

struct SwiftUIView: View {
  @State var date = Date()
    var body: some View {
      DatePicker(date: self.$date)
  }
}

回答1:


Here is possible approach. Tested with Xcode 11.2 / iOS 13.2

struct DatePicker: UIViewRepresentable {
    @Binding var date: Date

    private let datePicker = UIDatePicker()

    func makeUIView(context: Context) -> UIDatePicker {
        datePicker.datePickerMode = .date
        datePicker.addTarget(context.coordinator, action: #selector(Coordinator.changed(_:)), for: .valueChanged)
        return datePicker
    }

    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        datePicker.date = date
    }

    func makeCoordinator() -> DatePicker.Coordinator {
        Coordinator(date: $date)
    }

    class Coordinator: NSObject {
        private let date: Binding<Date>

        init(date: Binding<Date>) {
            self.date = date
        }

        @objc func changed(_ sender: UIDatePicker) {
            self.date.wrappedValue = sender.date
        }
    }
}



回答2:


An extended DatePicker approach with optional parameters (based on @Asperi answer).

struct DatePickerUIKit: UIViewRepresentable {
    @Binding private var selection: Date

    private let range: ClosedRange<Date>?

    private var minimumDate: Date? {
         range?.lowerBound
    }

    private var maximumDate: Date? {
        range?.upperBound
    }

    private var minuteInterval: Int

    private let datePicker = UIDatePicker()

    init(selection: Binding<Date>, in range: ClosedRange<Date>?, minuteInterval: Int = 1) {
        self._selection = selection
        self.range = range
        self.minuteInterval = minuteInterval
    }

    func makeUIView(context: Context) -> UIDatePicker {
        datePicker.datePickerMode = .dateAndTime
        datePicker.minuteInterval = minuteInterval
        datePicker.minimumDate = minimumDate
        datePicker.maximumDate = maximumDate
        datePicker.addTarget(context.coordinator, action: #selector(Coordinator.changed(_:)), for: .valueChanged)
        return datePicker
    }

    func updateUIView(_ uiView: UIDatePicker, context: Context) {
        datePicker.date = selection

    }

    func makeCoordinator() -> DatePickerUIKit.Coordinator {
        Coordinator(selection: $selection, in: range, minuteInterval: minuteInterval)
    }

    class Coordinator: NSObject {
        private let selection: Binding<Date>
        private let range: ClosedRange<Date>?
        private let minuteInterval: Int

        init(selection: Binding<Date>, in range: ClosedRange<Date>? = nil, minuteInterval: Int = 1) {
            self.selection = selection
            self.range = range
            self.minuteInterval = minuteInterval
        }

        @objc func changed(_ sender: UIDatePicker) {
            self.selection.wrappedValue = sender.date
        }
    }
}

For example to set the minute interval, that is not supported by SwiftUI yet:

@State var dateFrom = Date()

let minMaxRange = Date().dateAtStartOf(.day)...Date().dateAtEndOf(.day) + 3.days

DatePickerUIKit(selection: $dateFrom, 
             range: minMaxRange, minuteInterval: 30)


来源:https://stackoverflow.com/questions/59849818/swiftui-how-to-create-custom-uidatepicker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!