Как управлять firstResponder с двумя UITextFields с помощью ввода UIDatePicker - PullRequest
1 голос
/ 13 июня 2019

У меня есть ViewController с двумя UITextFields, которые используют UIDatePicker(s) для ввода. Одна - дата «От», а другая - дата «До», так что это выглядит довольно распространенным сценарием.

Проблема в том, что когда DatePicker одного поля активен, пользователь может нажать на другое поле на экране. Активный DatePicker по-прежнему привязан к первому полю, поэтому пользовательский интерфейс вводит в заблуждение пользователей, поскольку курсор мигает в другом поле, но ввод не идет туда.

Я думаю, что правильное решение для пользовательского интерфейса состоит в том, чтобы пользователь не мог подключиться к любому другому полю, пока 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?

1 Ответ

0 голосов
/ 13 июня 2019

Вы можете зарегистрировать делегат 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

...