Muhammad Awais Jamil
Muhammad Awais Jamil

Reputation: 406

How to know if Inline Date picker is switch between Yearly and Weekly view in iOS using swift?

I am using UIDatePicker with inline style. A month-year action appears at top left. I want to know if this action is being clicked of Month-Year wheel is appears on the screen.

Basically i want to disable Apply button if user is selecting Month-Year. Or is there any way to switch back to calendar view? Month-Year ViewCalender View

Upvotes: -1

Views: 479

Answers (1)

Sweeper
Sweeper

Reputation: 274358

There is no "proper" way to do this. You should make your own date picker.

That said, disabling the "Apply" button when the month-year selector is shown is rather bad design in my opinion. It's not like the selected date will be undefined or anything like that when the month-year selector is shown. When you change the month/year, the day-of-month would stay the same, or become the last day of the month if that month doesn't have that particular day-of-month.

Some people might have the habit of selecting the day-of-month first on the calendar, then selecting the year and month. For these people, disabling "Apply" would require them to dismiss the month-year picker as an extra step.

If you want an "improper" way (which might break in future iOS versions), here is one that works on iOS 17. You traverse the view hierarchy to find a _UICalendarHeaderView. Its third subview (also the only subview of type UIView) is the month-year selector button. This view has a gesture recogniser, to which you can addTarget.

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 tapped() {
    // ...
}

// in viewDidLoad
if let headerClass = NSClassFromString("_UICalendarHeaderView"),
   let header = findViewInViewHierarchy(root: datePicker, target: headerClass),
   header.subviews.count >= 3,
   let recognisers = headers.subviews[2].gestureRecognizers,
   recognisers.count > 0 {
    // doing all the above checks just in case this fails in a future version
    headers.subviews[2].gestureRecognizers?[0].addTarget(self, action: #selector(tapped))
}

In tapped, if you want to know if the month-year picker is displayed, you can find a _UICalendarMonthYearSelector. If you don't find one, or if its size is 0, that means the month-year selector is about to be shown.

See also this related answer of mine.

if let selectorClass = NSClassFromString("_UICalendarMonthYearSelector"),
   let monthYearSelector = findViewInViewHierarchy(root: datePicker, target: selectorClass)),
   monthYearSelector.bounds.size ==. zero {
    // disable "Apply"
} else {
    // enable "Apply"
}

Upvotes: 1

Related Questions