1

I am trying to dismiss a datePicker during selection of date by addTarget function. After when I select year it dismiss before I select date and when I select the date first I cannot select year. what I actually want is, during selection of year it shouldn't dismiss. It should dismiss when I select date. Is there any possible solution for this with using UIdatePicker ?

This is my code

let datePicker : UIDatePicker = {
    let date = UIDatePicker()
    date.datePickerMode = .date
    date.preferredDatePickerStyle = .compact
    date.tintColor =  UIColor(red: 83/255, green: 176/255, blue: 184/255, alpha: 1)
    return date
}()
func config() {
    datePicker.addTarget(self, action: #selector(selectButtonAction), for: .primaryActionTriggered)
}
@objc func selectButtonAction() {
    // code logic ...

    dismiss(animated: true)
}
Fabio
  • 5,432
  • 4
  • 22
  • 24
  • I believe you can check what the user is selecting (month-year or the calendar) by traversing through the view hierarchy. But this is a *very very* fragile approach. – Sweeper Jun 29 '23 at 06:07

1 Answers1

0

If I understand correctly, you want to dismiss the current VC when the user selects a date in this state:

enter image description here

But you don't want to do anything if the user changes the month/year in this state:

enter image description here

There is no officially supported way to do this - you are not supposed to use a UIDatePicker in this way.

I suggest adding an "OK" button or something to that effect, to let the user confirm that they have selected a date. Think about the case of a user mis-taps on the calendar, and end up accidentally dismissing the whole VC. That's quite frustrating if you ask me.

If you really want a behaviour like this, I would suggest making your own date selector.

That said, the month-year selector is, after all, a UIView, and can be found in the view hierarchy. After some reverse-engineering, that view is called _UICalendarMonthYearSelector, as of iOS 16.

So theoretically, in selectButtonAction, you can try to find this view in the hierarchy, and do not dismiss if you found it. This is heavily subject to changes in the implementation of UIDatePicker and UICalendarView. This will probably break in the future.

func findViewInViewHierarchy(root: UIView, target: AnyClass) -> UIView? {
    if root.isKind(of: target) {
        return root
    }
    for subview in root.subviews {
        if let found = findViewInViewHierarchy(root: subview, target: target) {
            return found
        }
    }
    return nil
}

@objc func selectButtonAction() {
    // for .compact style date pickers, use presentedViewController.view! as the root
    // for .inline style date pickers, use the date picker itself as the root
    let monthYearSelector = findViewInViewHierarchy(root: presentedViewController.view!, target: NSClassFromString("_UICalendarMonthYearSelector")!)
    if calendar == nil {
        // dismiss...
    }
}

If you actually wanted to dismiss the pop up that a .compact style date picker shows, rather than self, see this answer of mine.

Sweeper
  • 213,210
  • 22
  • 193
  • 313