How can I move to the previous UITextField if the “Backspace” button is pressed and the text field is blank and in Swift 4?

流过昼夜 提交于 2019-12-02 04:13:33

You should subclass UITextField to implement the deleteBackward() function. Also, you should implement a protocol which has a function that executes when deleteBackward() is called and the text is empty.

DISCLAIMER: This code's origin is in the VENTokenField project. It was converted to Swift and tweaked by me.

class BackspaceTextField: UITextField {
    weak var backspaceTextFieldDelegate: BackspaceTextFieldDelegate?

    override func deleteBackward() {
        if text?.isEmpty ?? false {
            backspaceTextFieldDelegate?.textFieldDidEnterBackspace(self)
        }

        super.deleteBackward()
    }
}

protocol BackspaceTextFieldDelegate: class {
    func textFieldDidEnterBackspace(_ textField: BackspaceTextField)
}

Instead of handling each text field separately, create an array of text fields in your view controller and handle first responders there. If there is a previous view controller, this sets it as the first responder (you don't need to resign anything, as the previous responder will automatically resign after the change). If it's the first text field in the array, it ends editing.

class ViewController: UIViewController, BackspaceTextFieldDelegate {
    var textField1: BackspaceTextField!
    var textField2: BackspaceTextField!
    [...]

    var textFields: [BackspaceTextField] {
        return [textField1, textField2, [...]]
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        textFields.forEach { $0.backspaceTextFieldDelegate = self }
    }

    func textFieldDidEnterBackspace(_ textField: BackspaceTextField) {
        guard let index = textFields.index(of: textField) else {
            return
        }

        if index > 0 {
            textFields[index - 1].becomeFirstResponder()
        } else {
            view.endEditing(true)
        }
    }
}

Regarding the blinking blue line, use tintColor:

textfield.tintColor = UIColor.black

You can use the textfield's background color to hide it.

Regarding Question 1:

Change the tint color of the text field as @Jon mentioned.

Regarding Question 2:

What I did was create an extension for the TextFieldDelegate. Within that, I created an additional function to alert, using NotificationCenter.default as the function needed to be defined in the present class.

extension UITextFieldDelegate {
    func deleteSelected(field: UITextField) {
        NotificationCenter.default.post(name: Notification.Name("deleteSelected"), object: field)
    }
}

Note, that in order for this to work correctly, you must call the function when the delete key was pressed. This can be done in your subclass of UITextField, by providing:

override func deleteBackward() {
    super.deleteBackward()
    delegate?.deleteSelected(field: self)
}

Finally, you need to listen for the event by adding an observer to that notification in the view you want to take action on.

NotificationCenter.default.addObserver(self, selector: #selector(checkForDelete(_ :)), name: Notification.Name("deleteSelected"), object: nil)

If you have not defined checkForDelete(_ :), this is what mine looks like:

@objc func checkForDelete(_ notification: Notification) {
    if let field = notification.object as? MyTextField {
        if let textFound = field.text, !textFound.isEmpty {
            //  Do nothing extra
            print("Text found: \(textFound).")
        } else {
            //  Go to previous field
            guard let activeField = active(textField: field).field, let index = active(textField: field).index else {
                print("Field could not be determined")
                return
            }
            print("Going backwards")
            activeField.text = nil
            activeField.resignFirstResponder()
            activeField.stateOfTextField = .empty
            textFields[index == 0 ? 0 : index - 1].becomeFirstResponder()
            textFields[index == 0 ? 0 : index - 1].text = nil
        }
    }
}

The 'Guard' in the else statement determines what the currently active text field is, and returns the index (they are stored in an array) so we can go to the previous TextField, if there is one.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!