skip to Main Content

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.)

2

Answers


  1. Use below.

    extension YourVC : UITextFieldDelegate {
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let currentString = (textField.text ?? "") as NSString
            var newString = currentString.replacingCharacters(in: range, with: string)
            
            let textFieldText = textField.text as NSString?
            let value = textFieldText?.replacingCharacters(in: range, with: string) ?? ""
            let finalText : String = ((value.replacingOccurrences(of: " ", with: "").count > 6) ? (textFieldText ?? "") as String : value)
            textField.setText(to: finalText.grouping(every: 2, with: "/"), preservingCursor: true)
            return false
        }
    }
    
    
    extension String {
        func grouping(every groupSize: String.IndexDistance, with separator: Character) -> String {
            let cleanedUpCopy = replacingOccurrences(of: String(separator), with: "")
            return String(cleanedUpCopy.enumerated().map() {
                $0.offset % groupSize == 0 ? [separator, $0.element] : [$0.element]
            }.joined().dropFirst())
        }
    }
    
    extension UITextField {
        public func setText(to newText: String, preservingCursor: Bool) {
            if preservingCursor {
                let cursorPosition = offset(from: beginningOfDocument, to: selectedTextRange!.start) + newText.count - (text?.count ?? 0)
                text = newText
                if let newPosition = self.position(from: beginningOfDocument, offset: cursorPosition) {
                    selectedTextRange = textRange(from: newPosition, to: newPosition)
                }}
            else{
                text = newText
            }
        }
    }
    
    Login or Signup to reply.
  2. 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


    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 first char is 0
      • allow 0, 1 or 2 if the first 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search