swift - 如何使用 UIDatePicker 输入管理具有两个 UITextField 的 firstResponder
问题描述
我有一个用于输入的ViewController
两个。一个是“From”日期,另一个是“To”日期,所以这似乎是一个相当常见的场景。UITextFields
UIDatePicker(s)
问题是当一个字段的 DatePicker 处于活动状态时,用户可能会点击屏幕上的另一个字段。活动的 DatePicker 仍然与第一个字段相关联,因此 UI 让用户感到困惑,因为光标在另一个字段中闪烁,但输入并没有转到那里。
我认为正确的 UI 解决方案是防止用户进入任何其他字段,直到 DatePicker 被解雇。但是我无法找到一种方法来检测 firstResponder 正在更改或暂时禁用其他字段的编辑。
这是我当前的代码没有做我需要做的事情:
class AddTripLocationVC: UIViewController, UITextFieldDelegate {
@IBOutlet private weak var tripLocFromDateInput: UITextField!
@IBOutlet private weak var tripLocToDateInput: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//set up datepickers for text field inputs
createDatePicker(forDateField: tripLocFromDateInput)
createDatePicker(forDateField: tripLocToDateInput)
}
//automatically update the label fields when the date vairables are updated by the UIDatePicker
var locFromDate: Date? {
didSet {
guard locFromDate != nil else { return }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"
tripLocFromDateInput.text = dateFormatter.string(from: locFromDate!)
}
}
var locToDate: Date? {
didSet {
guard locToDate != nil else { return }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"
tripLocFromDateInput.text = dateFormatter.string(from: locToDate!)
//Comment after solution found...The problem was the line above
//It should be:
tripLocToDateInput.text = dateFormatter.string(from: locToDate!)
}
}
func createDatePicker(forDateField dateField: UITextField) {
let datePickerView = UIDatePicker()
datePickerView.datePickerMode = .date
dateField.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(handleDatePicker(sender:)), for: .valueChanged)
let doneButton = UIBarButtonItem.init(title: "Done", style: .done, target: self, action: #selector(self.datePickerDone))
let toolBar = UIToolbar.init(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 44))
toolBar.setItems([UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil), doneButton],
animated: true)
dateField.inputAccessoryView = toolBar
}
@objc
func handleDatePicker(sender: UIDatePicker) {
if tripLocFromDateInput.isFirstResponder {
locFromDate = sender.date
} else {
if tripLocToDateInput.isFirstResponder {
locToDate = sender.date
} else {
print("Error: Can't find first responder field.")
}
}
}
@objc
func datePickerDone(dateField: UITextView) {
if tripLocFromDateInput.isFirstResponder {
tripLocFromDateInput.resignFirstResponder()
} else {
if tripLocToDateInput.isFirstResponder {
tripLocToDateInput.resignFirstResponder()
} else {
print("Error: Can't find first responder field.")
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
textField.becomeFirstResponder()
}
}
iOS 中这种类型的“从”和“到”日期字段的 UI 是否有“标准”方法?
解决方案
您可以注册一个 UITextField 委托,其中包含您特别感兴趣的两种方法,特别是:
textFieldDidBeginEditing(:)
textFieldDidEndEditing(:)
要获取更多信息,请访问:https ://developer.apple.com/documentation/uikit/uitextfielddelegate
请注意,您还可以becomeFirstResponder()
在任何 UITextField 上使用以使其处于活动状态。无论哪个处于活动状态,都应该有闪烁的光标。
编辑:根据您更新的代码:
//
// ViewController.swift
// datepickers
//
// Created by Dave Poirier on 2019-06-13.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet private weak var tripLocFromDateInput: UITextField!
@IBOutlet private weak var tripLocToDateInput: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//set up datepickers for text field inputs
createDatePicker(forDateField: tripLocFromDateInput)
createDatePicker(forDateField: tripLocToDateInput)
//set text field delegates to be notified when focus changes
tripLocFromDateInput.delegate = self
tripLocToDateInput.delegate = self
}
func createDatePicker(forDateField dateField: UITextField) {
let datePickerView = UIDatePicker()
datePickerView.datePickerMode = .date
dateField.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(handleDatePicker(sender:)), for: .valueChanged)
let doneButton = UIBarButtonItem.init(title: "Done", style: .done, target: self, action: #selector(self.datePickerDone))
let toolBar = UIToolbar.init(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 44))
toolBar.setItems([UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil), doneButton],
animated: true)
dateField.inputAccessoryView = toolBar
}
@objc
func handleDatePicker(sender: UIDatePicker) {
if tripLocFromDateInput.isFirstResponder {
let locFromDate = sender.date
tripLocFromDateInput.text = "FROM: \(locFromDate)"
} else {
if tripLocToDateInput.isFirstResponder {
let locToDate = sender.date
tripLocToDateInput.text = "TO: \(locToDate)"
} else {
print("Error: Can't find first responder field.")
}
}
}
@objc
func datePickerDone(dateField: UITextView) {
if tripLocFromDateInput.isFirstResponder {
tripLocFromDateInput.resignFirstResponder()
} else {
if tripLocToDateInput.isFirstResponder {
tripLocToDateInput.resignFirstResponder()
} else {
print("Error: Can't find first responder field.")
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.view.endEditing(true)
}
}
}
上面的代码在一个全新的项目中为我工作,创建了两个输入字段并连接了 IBOutlets
推荐阅读
- c++ - 检查新添加的 unique_ptr 到 priority_queue 的位置
- java - 无法在 java 中解析 subjectAlternativeNames
- jpa - @Any 字段和 @NamedEntityGraph
- mysql - windows无法在本地计算机上启动mysql服务错误1067
- css - ReactJS 材质 makeStyles
- javascript - 这在 HTML、JS 和 CSS 位于一个文件中时有效,但在它们位于不同文件中时无效
- html - 不同高度的 CSS 翻转效果
- javascript - JS中重构对象的最佳方式
- android - Androidx BottomNavigationView 在不同设备中的行为异常
- flutter - 如何使用颤振应用访问安卓手机的加速度传感器?