Search code examples
iosswiftuikituitextfield

Detecting a specific key [specifically the back/ return/ delete key] on the iPhone keyboard in swift


Before I get asked, no this is not a duplicate. No other question addresses this that I found with a satisfying answer.

I have been working on some code to make a data interface and I didn't want to use a date picker.

This is the code I'm using to get the XX/XX/XX format:

extension OneCreateAccountViewController {
    func textFieldDidChangeSelection(_ textField: UITextField) {
        
        if textField.placeholder == "DD/MM/YY" {

            
            if textField.text!.count >= 2 && textField.text!.count < 3  {

                textField.text! = "\(textField.text!)/"

            } else {
                
                if textField.text!.count >= 5 && textField.text!.count < 6   {

                    textField.text! = "\(textField.text!)/"

                } else {
                    
                    if textField.text!.count >= 9 {
                        
                        textField.text!.removeLast()
                   
                    }
                }
            }
        }
    }
}

As you can see it is pretty barebones, but my issue is that once "/" is inserted, no matter what happens, you cannot remove using the return key. I want a specific else statement that would work something like "else - if the backspace is returned and the last character is "", delete that character."

please help me in SPECIFICALLY HAVING A CODE THAT REGISTERS THE RETURN KEY (even if it is a simple "if return is pressed, print ("Hi")" like answer.)


Solution

  • You will have a lot of trouble trying to do this with only textFieldDidChangeSelection ...

    To answer your specific "CODE THAT REGISTERS THE RETURN KEY" question, implement textFieldShouldReturn in your UITextFieldDelegate:

    extension OneCreateAccountViewController: UITextFieldDelegate {
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            print("Enter key pressed")
            // Handle Enter key processing here
            return true
        }
        
    }
    

    To detect Backspace, implement shouldChangeCharactersIn:

    extension OneCreateAccountViewController: UITextFieldDelegate {
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            
            if string.isEmpty {
                print("Backspace detected")
                // Handle any additional backspace processing here
            }
    
            return true
    
        }
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            print("Enter key pressed")
            // Handle Enter key processing here
            return true
        }
        
    }
    

    Important note!! - that will fail due to a bug in the iOS simulators! It does work on an iOS 15.0 simulator, and I've seen notes that the bug is fixed in iOS 17.4 simulator.


    For the simplest approach, handle each new input in shouldChangeCharactersIn:

    extension OneCreateAccountViewController: UITextFieldDelegate {
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            
            // get the current text from the text field
            //  set it to "" if the text field is empty
            var theText = textField.text ?? ""
            
            if string.isEmpty {
                print("Backspace detected")
                // if the text field is empty, just ignore
                if theText.count == 0 {
                    return false
                }
                // remove the last character from the string
                theText.removeLast()
                // if the string was, for example, "12/1"
                //  it will now be "12/"
                //  so remove the trailing slash
                if theText.last == "/" {
                    theText.removeLast()
                }
                // update the text field
                textField.text = theText
                
                // don't allow built-in processing
                return false
            }
            
            // it wasn't backspace
        
            // if it's not a digit, or we already have 8 characters ("nn/nn/nn"), discard the new input
            if theText.count == 8 || !"0123456789".contains(string) {
                return false
            }
            
            // if the current text is "nn" or "nn/nn"
            //  append a slash
            if theText.count == 2 || theText.count == 5 {
                theText += "/"
            }
            // append the new input
            theText += string
            
            // update the text field
            textField.text = theText
            
            // don't allow built-in processing
            return false
            
        }
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            
            print("Enter key pressed")
            // Handle Enter key processing here
            return true
            
        }
        
    }
    

    Your task will be, however, rather more complex...

    For example, suppose the user has typed 25/12/2 and moves the caret / insertion point:

    caret

    What should happen if a 0 is typed? Or a backspace? Do you want to insert/delete where the caret is, reformat the slashes if necessary, maintain the caret location, and so on.


    And what do you want to happen if the user types 98/76/54?

    Ideally (I expect) you will want to validate every "keystroke":

    • if it's the first character
      • allow only 0, 1, 2 or 3
    • if it's the 2nd character
      • allow 1-9 if first char is 0
      • allow 0-9 if the first char is 1 or 2
      • allow 0 or 1 if the first char is 3
    • if it's the 4th character (immediately following the first slash)
      • allow only 0 or 1
    • if it's the 5th character
      • allow 1-9 if fourth char is 0
      • allow 0, 1 or 2 if the fourth char is 1

    and so on.

    Of course, if the user types 02/3 or 06/31 or 05/38 (etc), you'll also need to reject that last input.