'Open UIDatePicker programmatically in iOS 14
I have this normal UIDatePicker
(sorry that it's not in English, please ignore that):
But the problem is that it only appears when I'm pressing the Date Picker:
And I wanted to know how to show the Date Picker like in the first image (that it's covering all the screen with the blur effect) only with code, so the user won't need to press the Date Picker to show the date selector. Thanks.
Solution 1:[1]
You can use a datePicker with .compact
style and put a UILabel
on top of it and give it a background color to hide the datePicker
behind it, and make sure the label user interaction is disabled then you should be able to tap on the datePicker and it will show the modal and then the value changed of the datePicker you can use your own date formatter to set the text of the label accordingly, you might also both the datePicker and the label inside a UIView
and make it clip to bounds
Solution 2:[2]
I have the same problem. Im using following hack:
let datePicker = UIDatePicker(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
datePicker.preferredDatePickerStyle = .compact
// Removes Labels
datePicker.subviews.forEach({ $0.subviews.forEach({ $0.removeFromSuperview() }) })
Then I simply add this date picker on top of a view, which should open this popup.
Solution 3:[3]
It's impossible to open a UIDatePicker
with UIKit14
from within the code
UIDatePicker
has no API for doing thisUIKit
doesn't allow us to create aUIEvents
orUITouch
object which has any impact onUIKit
.
Solution 4:[4]
Unfortunately it's not possible to programatically display the date selector popup, at least not resorting to hacks that might result in your app being rejected:
the UIDatePicker control doesn't expose any events that can be programatically triggered via
sendActions(for:)
-allControlEvents
returns an empty option setprogramatically simulating a user click is officially impossible on iOS - there is no public API to achieve this, all workarounds imply resorting to private API's
if the above wouldn't be enough, the UI structure of UIDatePicker is composed of private classes:
The conclusion is that in its current state, the UIDatePicker
UI can be controlled only via user interactions. Maybe this will change in the future, for example UIButton
's expose actions for triggering the same behaviour as when the user tapped the button, so maybe UIDatePicker
will expose such actions in the future.
Solution 5:[5]
UPDATE: THIS IS NOT WORKING ANYMORE ON iOS 15.
@Amr Mohamed 's answer is clever by putting a label on the date picker view, but this also causes a glitch when tapping the date picker view, when the date picker vc animates out, you can also see the date picker.
So we need to "hide" the date picker view but also leave it interactive. (We can't just use isHidden = true
or alpha = 0
, otherwise it's not tappable anymore)
This is how I did in my project:
extension UIView {
func loopDescendantViews(_ closure: (_ subView: UIView) -> Void) {
for v in subviews {
closure(v)
v.loopDescendantViews(closure)
}
}
}
let datePicker = UIDatePicker()
datePicker.preferredDatePickerStyle = .compact
datePicker.loopDescendantViews {
$0.alpha = $0 is UIControl ? 1 : 0
}
Then you can put this invisible date picker on top of your label/other view. once you tap the label (actually tapped the date picker), the date picker vc animates out.
Solution 6:[6]
I don't know if this is still valid, but you can make use of the .inline
style of new UIDatePicker. Then use your own view and animations to mimic the appearance of the DatePicker from .compact
style.
let secondDatePicker = UIDatePicker()
secondDatePicker.preferredDatePickerStyle = .inline
self.view.addSubview(secondDatePicker)
secondDatePicker.translatesAutoresizingMaskIntoConstraints = false
secondDatePicker.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
secondDatePicker.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
Solution 7:[7]
You can set the preferred style of the date picker to "inline" from the storyboard. By doing this, you will directly get the full screen for date selection directly.
here is how the date picker looks for preferred style "compact"( the one you have):
vs "inline" ( the one you are looking for):
Solution 8:[8]
I think the only non-hacky approach is to create a new view controller, add a UIDatePicker instance in it with the embedded style, then present the controller modally or as a popover.
Solution 9:[9]
Just to be sure we're not missing the obvious here, the .inline style displays the full calendar without the user needing to click a date or time label. With that ability one could arrange any behavior they want with regard to displaying the calendar and selected/default dates, etc...
Solution 10:[10]
It works to switch to the old style of date picker:
if (@available(iOS 13.4, *)) {
[datePicker setPreferredDatePickerStyle:UIDatePickerStyleWheels];
}
Solution 11:[11]
Define these variables
var datePicker: UIDatePicker!
var datePickerConstraints = [NSLayoutConstraint]()
var blurEffectView: UIView!
Then create a function showDatePicker()
that you call to trigger the display of the UIDatePicker
. First, create a subview with the same size of his parent View and give it a blur effect. Then add the UIDatePicker
, as a subview on top of the blurred view.
func showDatePicker() {
datePicker = UIDatePicker()
datePicker?.date = Date()
datePicker?.locale = .current
datePicker?.preferredDatePickerStyle = .inline
datePicker?.addTarget(self, action: #selector(dateSet), for: .valueChanged)
addDatePickerToSubview()
}
func addDatePickerToSubview() {
guard let datePicker = datePicker else { return }
// Give the background Blur Effect
let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.regular)
blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(blurEffectView)
self.view.addSubview(datePicker)
datePicker.translatesAutoresizingMaskIntoConstraints = false
centerDatePicker()
view.bringSubviewToFront(datePicker)
}
func centerDatePicker() {
guard let datePicker = datePicker else { return }
// Center the Date Picker
datePickerConstraints.append(datePicker.centerYAnchor.constraint(equalTo: self.view.centerYAnchor))
datePickerConstraints.append(datePicker.centerXAnchor.constraint(equalTo: self.view.centerXAnchor))
NSLayoutConstraint.activate(datePickerConstraints)
}
And finally, once a date a selected in the UIDatePicker
@objc func dateSet() {
// Get the date from the Date Picker and put it in a Text Field
compactDatePicker.date = datePicker.date
blurEffectView.removeFromSuperview()
datePicker.removeFromSuperview()
}
Not entirely sure about the blurr effect so hopefully someone can build on this solution.
Solution 12:[12]
Date picker changed in iOS v14.0 before that it was an inline wheel. Now in iOS v14.0 what you can do is tell it to be inline and it will show the calendar inline (no popup):
if #available(iOS 14.0, *) {
datePicker.preferredDatePickerStyle = UIDatePickerStyle.inline
}
Note: you may need to fix the frame size as the datepicker will look different in iOS 13 (wheel) and iOS 14 (calendar), so you will probably need an "else" for version 13..
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow