Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DatePicker using Time-Interval in SwiftUI

I want to use a DatePicker in SwiftUI, it is working fine and as expected. I want to add an Time-interval, like explained: UIDatePicker 15 Minute Increments Swift

DatePicker("Please enter a time", selection: $wakeUp, displayedComponents: .hourAndMinute)

Is there a Modifier for that in SwifUI?

like image 706
Jonas Deichelmann Avatar asked Feb 24 '20 13:02

Jonas Deichelmann


3 Answers

I don't believe there is a modifier for this. However it's possible to "do it yourself" by using UIViewRepresentable to wrap a UIDatePicker:

The basic structure for this code is based on the Interfacing with UIKit tutorial.

struct MyDatePicker: UIViewRepresentable {

    @Binding var selection: Date
    let minuteInterval: Int
    let displayedComponents: DatePickerComponents

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    func makeUIView(context: UIViewRepresentableContext<MyDatePicker>) -> UIDatePicker {
        let picker = UIDatePicker()
        // listen to changes coming from the date picker, and use them to update the state variable
        picker.addTarget(context.coordinator, action: #selector(Coordinator.dateChanged), for: .valueChanged)
        return picker
    }

    func updateUIView(_ picker: UIDatePicker, context: UIViewRepresentableContext<MyDatePicker>) {
        picker.minuteInterval = minuteInterval
        picker.date = selection

        switch displayedComponents {
        case .hourAndMinute:
            picker.datePickerMode = .time
        case .date:
            picker.datePickerMode = .date
        case [.hourAndMinute, .date]:
            picker.datePickerMode = .dateAndTime
        default:
            break
        }
    }

    class Coordinator {
        let datePicker: MyDatePicker
        init(_ datePicker: MyDatePicker) {
            self.datePicker = datePicker
        }

        @objc func dateChanged(_ sender: UIDatePicker) {
            datePicker.selection = sender.date
        }
    }
}

struct DatePickerDemo: View {
    @State var wakeUp: Date = Date()
    @State var minterval: Int = 1

    var body: some View {
        VStack {
            Stepper(value: $minterval) {
                Text("Minute interval: \(minterval)")
            }
            MyDatePicker(selection: $wakeUp, minuteInterval: minterval, displayedComponents: .hourAndMinute)
            Text("\(wakeUp)")
        }
    }
}

struct DatePickerDemo_Previews: PreviewProvider {
    static var previews: some View {
        DatePickerDemo()
    }
}

like image 154
jtbandes Avatar answered Oct 11 '22 02:10

jtbandes


Not fully a SwiftUI solution, but much simpler than the existing answer. Attach this to your main body View that contains the picker

.onAppear {
    UIDatePicker.appearance().minuteInterval = 5
}

The one downside is this will apply to all pickers in the view and can affect pickers in other views in the app, but you can always do the same thing in those views (set minute interval back to 1).

like image 23
DarkAgeOutlaw Avatar answered Oct 11 '22 01:10

DarkAgeOutlaw


It is also possible with Introspect lib

DatePicker(...)
    .introspectDatePicker {
        $0.minuteInterval = 30
        $0.roundsToMinuteInterval = true
    }
like image 1
imike Avatar answered Oct 11 '22 02:10

imike