How can I move to the previous UITextField if the "Backspace" button is pressed and the text field is blank and in Swift 4?
Asked Answered
M

4

3

I am trying to figure this out. When I use the code below, I am able to move from one text field to the next and click the "Backspace" button but ONLY when the text field has text in there.

My Question: How can I click the "Backspace" button when the text field is blank and move to the previous text field?

Second Question: How do I get rid of the blinking blue line on the UITextField?

Below is the code that I have. Any help will be greatly appreciated!

@objc func textFieldDidChange(textfield: UITextField) {
    let text = textfield.text!
    if text.utf16.count == 0 {
        switch textfield {
        case textField2:
            textField1.becomeFirstResponder()
            textField1.backgroundColor = UIColor.black
        case textField3:
            textField2.becomeFirstResponder()
            textField2.backgroundColor = UIColor.black
        case textField4:
            textField3.becomeFirstResponder()
            textField3.backgroundColor = UIColor.black
        case textField5:
            textField4.becomeFirstResponder()
            textField4.backgroundColor = UIColor.black
        case textField6:
            textField5.becomeFirstResponder()
            textField5.backgroundColor = UIColor.black
            textField6.resignFirstResponder()
            textField6.backgroundColor = UIColor.black
        default:
            break
        }
    }
    else if text.utf16.count == 1 {
        switch textfield {
        case textField1:
            textField1.backgroundColor = UIColor.black
            textField1.textColor = .white
            textField2.becomeFirstResponder()
            textField2.backgroundColor = UIColor.black
            textField2.textColor = .white
        case textField2:
            textField3.becomeFirstResponder()
            textField3.backgroundColor = UIColor.black
            textField3.textColor = .white
        case textField3:
            textField4.becomeFirstResponder()
            textField4.backgroundColor = UIColor.black
            textField4.textColor = .white
        case textField4:
            textField5.becomeFirstResponder()
            textField5.backgroundColor = UIColor.black
            textField5.textColor = .white
        case textField5:
            textField6.becomeFirstResponder()
            textField6.backgroundColor = UIColor.black
            textField6.textColor = .white
        case textField6:
            textField6.resignFirstResponder()
        default:
            break

        }
    }
}
Micheal answered 20/4, 2018 at 7:23 Comment(2)
I didn't recognize what exactly you want. But as per my understanding, you want to move on previous current textField when click on backspace if textField is empty, right ?Fanciful
Yes, that is correct!Micheal
L
4

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)
        }
    }
}
Lassie answered 20/4, 2018 at 8:19 Comment(2)
Thanks for this, but I could not get this to work on the above code... How can I get this code above to work on the code?Micheal
Where did you have an issue implementing this solution? Make sure you understand what the code does. If a detail is not clear, let me know.Mesne
V
1

Regarding the blinking blue line, use tintColor:

textfield.tintColor = UIColor.black

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

Vidovik answered 20/4, 2018 at 8:27 Comment(0)
B
0

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.

Beluga answered 9/5, 2018 at 17:50 Comment(0)
T
0

When you have four Textfields inputOne, inputTwo, inputThree, inputFour create 4 @IBOutlet like @IBOutlet weak var inputOne, @IBOutlet weak var inputOne, @IBOutlet weak var inputThree, @IBOutlet weak var inputFour

This is very simple by adding white space on beginning of TextField editing

if user enters the value like "1" to "9" next text field becomes first responder If user taps on backButton if textfield contains value replace that with white space and if user taps on backButton if textfield contains white space the previous textfield becomes first responder

Only i m using two TextField delegate Methods

  1. textFieldDidBeginEditing
  2. shouldChangeCharactersIn

func textFieldDidBeginEditing(_ textField: UITextField) {

    if(textField.text == ""){
        textField.text = " "
    } 

}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let maxLength = 1
    let currentString: NSString = textField.text! as NSString
    let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
    if let char = string.cString(using: String.Encoding.utf8) {
        let isBackSpace = strcmp(char, "\\b")
        if (isBackSpace == -92 && textField.text == " ") {
            if(textField.tag == 0){
                self.focusOnTextField(selTextField:inputOne)
         
                return false
            }else if(textField.tag == 1){
                self.focusOnTextField(selTextField:inputOne)
                
                return false
            }else if(textField.tag == 2){
                self.focusOnTextField(selTextField:inputTwo)
                
                return false
            }else if(textField.tag == 3){
                self.focusOnTextField(selTextField:inputThree)
                
                return false
            }
        }
        else if (isBackSpace == -92 && textField.text != " ") {
            textField.text = " "
            
            return false
        }
        else {
            textField.text = textField.text?.replacingOccurrences(of:textField.text!, with:string)
        }
    }
    
    let newPosition = textField.endOfDocument
    textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
    if(textField.tag == 0){
        self.focusOnTextField(selTextField:inputTwo)
    } else if(textField.tag == 1){
        self.focusOnTextField(selTextField:inputThree)
    }else if(textField.tag == 2){
        self.focusOnTextField(selTextField:inputFour)
    }
    return newString.length <= maxLength
}
 
func focusOnTextField(selTextField:UITextField) {       
        selTextField.becomeFirstResponder()
}
Trimetric answered 30/7, 2022 at 6:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.