'DatePicker not closing after tap outside
In my application I have a textfield to add the date of birth. I add a datePicker to popup once user tap on the textfield. datePicker display correctly and after user select the date it is displaying in the textfield. The problem is after select the date the datePicker is not closing.
This is my code:
class BController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var dateOfBirth: UITextField!
let datePicker = UIDatePicker()
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
// self.view.endEditing(true)
return true
}
func textFieldDidBeginEditing(textField: UITextField){
if textField == dateOfBirth{
// let datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePickerMode.Date
datePicker.backgroundColor = UIColor.blackColor()
datePicker.setValue(UIColor.whiteColor(), forKey: "textColor")
textField.inputView = datePicker
datePicker.addTarget(self, action: "datePickerChanged:", forControlEvents: .ValueChanged)
}
}
func datePickerChanged(sender: UIDatePicker){
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
// formatter.dateStyle = .ShortStyle
// formatter.timeStyle = .NoStyle
dateOfBirth.text = formatter.stringFromDate(sender.date)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
print("touch happened")
self.view.endEditing(true)
}
override func viewDidLoad() {
super.viewDidLoad()
dateOfBirth.delegate = self
text1.delegate = self
text2.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I got console output as:
unrecognized selector sent to instance 0x7 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[BController getCalendar:]: unrecognized selector sent to instance 0x78789050'
How to solve this issue? I'm using Xcode 6.2. If you need more information please let me know.
Solution 1:[1]
As documentation say:
var inputView: UIView? The custom input view to display when the text field becomes the first responder.
So you should first initialize your datePicker, and then assign it to dateOfBirth's inputView property in viewDidLoad method instead textFieldDidBeginEditing method.
For closing datePicker on tap outside use UITapGestureRecognizer added on self.view
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let datePicker = UIDatePicker.init()
textField.inputView = datePicker
let gestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(backgroundTap(gesture:)));
view.addGestureRecognizer(gestureRecognizer)
}
func backgroundTap(gesture : UITapGestureRecognizer) {
textField.resignFirstResponder() // or view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your mistake is that when textFieldDidBeginEditing method call, UITextField knows nothing about UIDatePicker.
Solution 2:[2]
I know this is an old question, and a slightly different approach to showing a date picker but I think the idea can still be applied.
Try wrapping the Date Picker View in a UIView() container which contains the gesture detector and spans the full size of the screen.
class ViewController: UIViewController {
var toolBar = UIToolbar()
var datePicker = UIDatePicker()
var datePickerContainer = UIView()
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func showDatePicker(_ sender: UIButton) {
datePicker = UIDatePicker()
datePicker.autoresizingMask = .flexibleWidth
datePicker.datePickerMode = .dateAndTime
datePicker.preferredDatePickerStyle = .wheels
datePicker.backgroundColor = .clear
datePicker.addTarget(self, action: #selector(self.dateChanged(_:)), for: .valueChanged)
datePicker.frame = CGRect(x: 0.0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 300)
datePickerContainer = UIView()
datePickerContainer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
datePickerContainer.backgroundColor = .clear
datePickerContainer.addSubview(datePicker)
self.view.addSubview(datePickerContainer)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(touchedOutsideOverlay(_:)))
datePickerContainer.addGestureRecognizer(tapGesture)
toolBar = UIToolbar(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 50))
toolBar.barStyle = .black
toolBar.items = [
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.onDoneButtonClick))
]
toolBar.sizeToFit()
self.view.addSubview(toolBar)
}
@objc func dateChanged(_ sender: UIDatePicker?) {
let dateFormatter = DateFormatter()
if let date = sender?.date {
print("Picked the date: \(dateFormatter.string(from: date))")
}
}
@objc func touchedOutsideOverlay(_ sender: UITapGestureRecognizer){
removeDatePicker()
}
@objc func onDoneButtonClick() {
removeDatePicker()
}
func removeDatePicker(){
toolBar.removeFromSuperview()
datePicker.removeFromSuperview()
datePickerContainer.removeFromSuperview()
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Paul Mayer |