如何使用UIDatePicker输入使用两个UITextField管理firstResponder

时间:2019-06-13 03:44:21

标签: swift uidatepicker

我有一个ViewController和两个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方法?

1 个答案:

答案 0 :(得分:0)

您可以注册一个UITextField委托,其中包含两个您特别感兴趣的方法,

  • textFieldDidBeginEditing(:)
  • textFieldDidEndEditing(:)

要获取更多信息,请访问:https://developer.apple.com/documentation/uikit/uitextfielddelegate

请注意,您还可以在任何UITextField上使用becomeFirstResponder()来激活一个。处于活动状态的光标应该闪烁。


编辑:根据您更新的代码:

//
//  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