Trying to open the Date picker popup on button tap but it is showing a label instead of picker, and on tapping that label the picker opens. Below is code:
@IBAction func changeMonth(_ sender: Any) {
let picker : UIDatePicker = UIDatePicker()
picker.datePickerMode = UIDatePicker.Mode.date
picker.addTarget(self, action: #selector(dueDateChanged(sender:)), for: UIControl.Event.valueChanged)
let pickerSize : CGSize = picker.sizeThatFits(CGSize.zero)
picker.frame = CGRect(x:0.0, y:250, width:pickerSize.width, height:460)
self.view.addSubview(picker)
}
@objc func dueDateChanged(sender:UIDatePicker){
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .none
dateFormatter.timeStyle = .none
btnMonth.setTitle(dateFormatter.string(from: sender.date), for: .normal)
}
Need this to open on button tap:
But this is being shown:
and on tapping of this date label, picker opens. I am not getting why picker not opening directly. Please guide what's wrong in above code.
Here is a very simple example of embedding the date picker in a view, then showing / hiding that view on a button tap:
class MyDatePicker: UIView {
var changeClosure: ((Date)->())?
var dismissClosure: (()->())?
let dPicker: UIDatePicker = {
let v = UIDatePicker()
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
let blurEffect = UIBlurEffect(style: .dark)
let blurredEffectView = UIVisualEffectView(effect: blurEffect)
let pickerHolderView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 8
return v
}()
[blurredEffectView, pickerHolderView, dPicker].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
addSubview(blurredEffectView)
pickerHolderView.addSubview(dPicker)
addSubview(pickerHolderView)
NSLayoutConstraint.activate([
blurredEffectView.topAnchor.constraint(equalTo: topAnchor),
blurredEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
blurredEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
blurredEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
pickerHolderView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20.0),
pickerHolderView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20.0),
pickerHolderView.centerYAnchor.constraint(equalTo: centerYAnchor),
dPicker.topAnchor.constraint(equalTo: pickerHolderView.topAnchor, constant: 20.0),
dPicker.leadingAnchor.constraint(equalTo: pickerHolderView.leadingAnchor, constant: 20.0),
dPicker.trailingAnchor.constraint(equalTo: pickerHolderView.trailingAnchor, constant: -20.0),
dPicker.bottomAnchor.constraint(equalTo: pickerHolderView.bottomAnchor, constant: -20.0),
])
if #available(iOS 14.0, *) {
dPicker.preferredDatePickerStyle = .inline
} else {
// use default
}
dPicker.addTarget(self, action: #selector(didChangeDate(_:)), for: .valueChanged)
let t = UITapGestureRecognizer(target: self, action: #selector(tapHandler(_:)))
blurredEffectView.addGestureRecognizer(t)
}
@objc func tapHandler(_ g: UITapGestureRecognizer) -> Void {
dismissClosure?()
}
@objc func didChangeDate(_ sender: UIDatePicker) -> Void {
changeClosure?(sender.date)
}
}
class ViewController: UIViewController {
let myPicker: MyDatePicker = {
let v = MyDatePicker()
return v
}()
let myButton: UIButton = {
let v = UIButton()
v.setTitle("Show Picker", for: [])
v.setTitleColor(.white, for: .normal)
v.setTitleColor(.lightGray, for: .highlighted)
v.backgroundColor = .blue
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
[myButton, myPicker].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// custom picker view should cover the whole view
myPicker.topAnchor.constraint(equalTo: g.topAnchor),
myPicker.leadingAnchor.constraint(equalTo: g.leadingAnchor),
myPicker.trailingAnchor.constraint(equalTo: g.trailingAnchor),
myPicker.bottomAnchor.constraint(equalTo: g.bottomAnchor),
myButton.centerXAnchor.constraint(equalTo: g.centerXAnchor),
myButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
myButton.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.75),
])
// hide custom picker view
myPicker.isHidden = true
// add closures to custom picker view
myPicker.dismissClosure = { [weak self] in
guard let self = self else {
return
}
self.myPicker.isHidden = true
}
myPicker.changeClosure = { [weak self] val in
guard let self = self else {
return
}
print(val)
// do something with the selected date
}
// add button action
myButton.addTarget(self, action: #selector(tap(_:)), for: .touchUpInside)
}
@objc func tap(_ sender: Any) {
myPicker.isHidden = false
}
}
Here's how it looks on start:
tapping the button will show the custom view:
and here's how it looks on iOS 13 (prior to the new UI):