Increase the tap area of UIDatePicker

Archana Kumari
3 min readDec 29, 2023
UIDate Picker opened calender

I am writing this blog as I have researched a lot online and have not found a solution to my problem.

Problem statement:

  • I have a UIDatePicker behind my dd/mm/yy view.
  • I needed to increase the tap area of that datePicker so that the whole field dd/mm/yy should open the calendar.

What are the things I tried:

  • Gave constraint to the datePicker so that it expands horizontally and can be tappable from anywhere on that field (It was just expanding the innermost layer of the datePicker which was not the exact view opening calendar)
  • Tried hittest to increase the tap of datePicker

But both of the above solutions did not work.

The solution I found which worked:

Looped through the inner views of the UIDatePicker and stretched it horizontally, so the label (Before iOS 17 version)/ button (from iOS 17 version) stretched internally horizontally and now the whole view is opening the calendar.

Before iOS 17:

There was UIView which was tappable inside the UIDatePicker inner layers and which opened the calendar

UIDatePicker increases tap area in iOS version < 17
public extension UIDatePicker {

func increaseTapArea() {
guard let view = subviews.first else { return }
for layoutguide in guides {
layoutguide.constraintsAffectingLayout(for: .horizontal).forEach { constraint in
if constraint.relation == .greaterThanOrEqual || constraint.relation == .lessThanOrEqual {
constraint.isActive = false
}
}
layoutguide.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
layoutguide.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
}
}

iOS 17 and above:

There is UIButton which is tappable inside the UIDatePicker inner layers and which opened the calendar.

UIDatePicker increases tap area in iOS version ≥17
public extension UIDatePicker {

func getDatePickerButton(view: UIView) -> UIButton? {
/// In iOS 17 and above swift has changed the internal components and added button inside datePicker, that is why getting button in iOS>=17 only else returning nil
if #available(iOS 17, *) {
if let button = view.subviews.first( where: { $0 is UIButton }) {
return button as? UIButton
} else {
return view.subviews.compactMap { getDatePickerButton(view: $0) }.first
}
} else {
return nil
}
}

func increaseTapArea() {
guard let view = subviews.first else { return }
let button = getDatePickerButton(view: self)
var guides: [UILayoutGuide] = view.layoutGuides
if let buttonGuide = button?.layoutMarginsGuide {
guides.append(buttonGuide)
}
for layoutguide in guides {
layoutguide.constraintsAffectingLayout(for: .horizontal).forEach { constraint in
if constraint.relation == .greaterThanOrEqual || constraint.relation == .lessThanOrEqual {
constraint.isActive = false
}
}
layoutguide.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
layoutguide.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
}
}

In the above code getDatePickerButton(view:) -> Button? returns the button inside UIDatePicker which opens the calender. And then inside increaeTapArea method stretches that button also.

Result:

UIDatePicker Before and After tappable area

Thank you for reading!

Please leave comments if you have any suggestion(s) or would like to add point(s) or if you noticed any mistakes or typos or any queries!

P.S. If you found this article helpful, clap! 👏👏👏 [feels rewarding and gives the motivation to continue my writing].

--

--