Search code examples
iosswiftuitextfieldphone-numbernsformatter

Formatting UITextField's text as Phone Number as user types in


I have a custom UITextField, which I am trying to 'format the input to phone number' as user types. What I want to achieve:

  • Adding a prefixed + sign on the UITextField as the first character, that cannot be deleted.

  • Format both the String variable and UITextField's text in the format of phone number nicely (+49 291 12345678), rather than plain numbers (4929112345678) as user types in.


I researched and found out that there is no built-in method for that. I've also found easy-to-use library called PhoneNumberKit for formatting the input String to Phone number. In Playground, it works like..

let rawNumberArray = "+4929112345678"
let phoneNumbers = PartialFormatter().formatPartial(rawNumberArray)

print(phoneNumbers) // "+49 291 12345678"

Bare in mind that, the library needs the String to have + as the first character to format properly.


I tried implementing it on my UITextField.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    if textField == myTextField {
        let candidateString : NSString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        let updatedTextString : NSString = PartialFormatter().formatPartial(candidateString as String)

        self.formattedPhoneNumber(updatedTextString, textField: textField)
    }
    return true
}

func formattedPhoneNumber(updatedTextString: NSString, textField: UITextField) {
    //  textField.text = "+\(updatedTextString as String)"
    print(updatedTextString)
}

If I keep textField.text = "+\(updatedTextString as String)" commented, print(updatedTextString) prints nicely formatted String on the console, BUT inside UITextField on UI, it just shows plain, unstructured numbers like "4929112345678"

If I uncomment it, things start to get weird and UITextField starts present duplicated characters in the UI, but console log for print also gets pretty weird. I also tried emptying textField.text = "" before, but didn't work either.


What am I doing wrong? What am I missing that doesn't let it work fine? I believe it's related with me and not the library itself.

Also, if you have any other suggestions (or libraries) for me to overcome this problem, please share them.


Solution

  • If you are changing the values you want to show, should return false after replacing the text. Here is an example:

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        if let text = textField.text {
            print("curText: \(text) range: \(range.location)-\(range.length) string: \(string)" )
    
            let candidate = (text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    
            if(!candidate.isCorrectFormat()){
                textField.text = callYourFormatMethodHere();
    
                return false
            }
    
        }
    
        return true
    }
    

    You need to implement your own isCorrectFormat() and callYourFormatMethodHere().

    Edit:

    Use your code:

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
    {
        if textField == myTextField {
            let candidateString : NSString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
            let updatedTextString : NSString = PartialFormatter().formatPartial(candidateString as String)
    
            self.formattedPhoneNumber(updatedTextString, textField: textField)
    
            return false // Return false here
        }
        return true
    }