I'm trying to display a datepicker when you tap on a textfield. This all seems to be working fine but as soon as I dismiss the date picker it will show the keyboard instead.
So I basically have to dismiss it 2 times before it will actually disappear.
I've created a textfield class for the picker which looks the following
EDIT MOVED ALL THE CODE INTO THE TEXTFIELD CLASS
protocol TextFieldPickerDelegate {
func pickerValueDidChange(date: Date, pickerMode: UIDatePickerMode, sender: TextFieldPicker)
}
public class TextFieldPicker: UITextField, UITextFieldDelegate {
var pickerMode: UIDatePickerMode = .date
@IBInspectable var pickerType: String? {
willSet {
for s in (newValue?.lowercased().getStrings())! {
switch s {
case "date":
pickerMode = .date
case "dateandtime":
pickerMode = .dateAndTime
case "countdowntimer":
pickerMode = .countDownTimer
case "time":
pickerMode = .time
default:
pickerMode = .date
}
}
}
didSet {
setupTextField()
}
}
var textFieldPickerDelegate: TextFieldPickerDelegate?
func setupTextField() {
createPicker()
}
override public func draw(_ rect: CGRect) {
super.draw(rect)
delegate = self
}
override public func caretRect(for position: UITextPosition) -> CGRect {
return CGRect.zero
}
override public func shouldChangeText(in range: UITextRange, replacementText text: String) -> Bool {
return false
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.resignFirstResponder()
return true
}
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
self.resignFirstResponder()
return true
}
func createPicker() {
let datePicker = UIDatePicker()
datePicker.datePickerMode = pickerMode
datePicker.addTarget(self, action: #selector(pickerValueChange(_:)), for: .valueChanged)
let pickerToolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44))
pickerToolBar.tintColor = UIColor.gray
let doneButton = UIBarButtonItem(title: NSLocalizedString("done", comment: ""), style: .done, target: self, action: #selector(closePicker(_:)))
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
pickerToolBar.setItems([space, doneButton], animated: true)
self.inputView = datePicker
self.inputAccessoryView = pickerToolBar
}
func closePicker(_ sender: Any) {
self.resignFirstResponder()
}
func pickerValueChange(_ sender: UIDatePicker) {
self.textFieldPickerDelegate?.pickerValueDidChange(date: sender.date, pickerMode: sender.datePickerMode, sender: self)
}
public func getDateString(date: Date, format: String) -> String {
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = format
return timeFormatter.string(from: date)
}
}
// =================================================== OptionSet =================================================== \\
public struct PickerModes: OptionSet {
private enum PickerMode: Int, CustomStringConvertible {
case Date=1
case DateAndTime=2
case CountDownTimer=4
case Time=8
public var description: String {
var shift = 0
while (rawValue.hashValue >> shift != 1) { shift += 1 }
return ["date", "dateandtime", "countdowntimer", "time"][shift]
}
}
public let rawValue: Int
public init(rawValue: Int) { self.rawValue = rawValue }
private init(_ mode: PickerMode) { self.rawValue = mode.rawValue }
static let Date = PickerModes(PickerMode.Date)
static let DateAndTime = PickerModes(PickerMode.DateAndTime)
static let CountDownTimer = PickerModes(PickerMode.CountDownTimer)
static let Time = PickerModes(PickerMode.Time)
}
extension String {
func getStrings() -> [String] {
var stringArray: [String] = []
let strings = self.characters.split{$0 == ","}.map(String.init)
for s in strings {
let string = s.removeSpaces()
stringArray.append(string)
}
return stringArray
}
func removeSpaces() -> String {
if self.characters.first == " " {
var copy = self
copy.characters.removeFirst()
return copy.removeSpaces()
} else {
return self
}
}
}
This class is entirely responsible for showing the date picker and dealing with displaying the correct type of date picker in case there are multiple different pickers needed in one screen.
EDIT 2
If anyone else tries my code it will work fine without any problems. The issue I was having is that I accidentally set my custom class to a UIView
that contained my UITextField
so when I tapped the textfield it would first trigger the keyboard for the UIView
and then the UIDatePicker
so when the UIDatePicker
was resigned the keyboard would still be there.
I have been doing some research and it seems to me that there are much easier methods of creating a date picker inside a text field. You could just use one of them. https://blog.apoorvmote.com/change-textfield-input-to-datepicker/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.