UITextField for Phone Number

Viewed 58514

I was wondering how I can format the textField that I'm using for a phone number (ie like the "Add New Contact" page on the iPhone. When I enter in a new mobile phone, ex. 1236890987 it formats it as (123) 689-0987.) I already have the keyboard set as the number pad.

25 Answers

Updated answer from Vikzilla for Swift 3:

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

    if textField == phoneTextField {

        let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
        let components = (newString as NSString).components(separatedBy: NSCharacterSet.decimalDigits.inverted)

        let decimalString = components.joined(separator: "") as NSString
        let length = decimalString.length
        let hasLeadingOne = length > 0 && decimalString.character(at: 0) == (1 as unichar)

        if length == 0 || (length > 10 && !hasLeadingOne) || length > 11 {
            let newLength = (textField.text! as NSString).length + (string as NSString).length - range.length as Int

            return (newLength > 10) ? false : true
        }
        var index = 0 as Int
        let formattedString = NSMutableString()

        if hasLeadingOne {
            formattedString.append("1 ")
            index += 1
        }
        if (length - index) > 3 {
            let areaCode = decimalString.substring(with: NSMakeRange(index, 3))
            formattedString.appendFormat("(%@)", areaCode)
            index += 3
        }
        if length - index > 3 {
            let prefix = decimalString.substring(with: NSMakeRange(index, 3))
            formattedString.appendFormat("%@-", prefix)
            index += 3
        }

        let remainder = decimalString.substring(from: index)
        formattedString.append(remainder)
        textField.text = formattedString as String
        return false

    } else {
        return true
    }
}

You can call this method whenever you need to update your textField:

extension String {
    func applyPatternOnNumbers(pattern: String, replacmentCharacter: Character) -> String {
        var pureNumber = self.replacingOccurrences( of: "[^0-9]", with: "", options: .regularExpression)
        for index in 0 ..< pattern.count {
            guard index < pureNumber.count else { return pureNumber }
            let stringIndex = String.Index(utf16Offset: index, in: pattern)
            let patternCharacter = pattern[stringIndex]
            guard patternCharacter != replacmentCharacter else { continue }
            pureNumber.insert(patternCharacter, at: stringIndex)
        }
        return pureNumber
    }
}

Example:

 guard let text = textField.text else { return }
 textField.text = text.applyPatternOnNumbers(pattern: "+# (###) ###-####", replacmentCharacter: "#")

Swift 5+

Its an updated version of @Дарія Прокопович answer.

extension String {
  func applyPatternOnNumbers(pattern:String = "+# (###) ###-####", replacmentCharacter:Character = "#") -> String {
        var pureNumber = self.replacingOccurrences( of: "[^0-9]", with: "", options: .regularExpression)
        for index in 0 ..< pattern.count {
            guard index < pureNumber.count else { return pureNumber }
            let stringIndex = String.Index(encodedOffset: index)
            let patternCharacter = pattern[stringIndex]
            guard patternCharacter != replacmentCharacter else { continue }
            pureNumber.insert(patternCharacter, at: stringIndex)
        }
        return pureNumber
    }
}

Usage:

 @IBAction func phoneTextFieldValueChanged(_ sender: Any) {
      phoneTextField.text = phoneTextField.text!.applyPatternOnNumbers()
 }

You can use this library https://github.com/luximetr/AnyFormatKit

Example

let textInputController = TextInputController()

let textInput = TextInputField() // or TextInputView or any TextInput
textInputController.textInput = textInput // setting textInput

let formatter = TextInputFormatter(textPattern: "### (###) ###-##-##", prefix: "+12")
textInputController.formatter = formatter // setting formatter

Just set your textField to this textInputController and it will format text with pattern, that you set.

Or

let phoneFormatter = TextFormatter(textPattern: "### (###) ###-##-##")
phoneFormatter.formattedText(from: "+123456789012") // +12 (345) 678-90-12

for format full string

Unfortunately, you have to do it yourself. The contact app uses undocumented APIs. For some reason attaching input formatters to text fields is not exposed on the iPhone the way it is on the Mac. Feel free to file a feature enhancement bug report.

u have to do to this manually . take a notification of textField and check length of field text and format it according to country. if any problem let me know. I have done this

This is my solution using Swift 4 to format a number of type (123) 689-0987

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let currentText:String = textField.text else {return true}
    if string.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) != nil { return false }
    let newCount:Int = currentText.count + string.count - range.length
    let addingCharacter:Bool = range.length <= 0

    if(newCount == 1){
        textField.text = addingCharacter ? currentText + "(\(string)" : String(currentText.dropLast(2))
        return false
    }else if(newCount == 5){
        textField.text = addingCharacter ? currentText + ") \(string)" : String(currentText.dropLast(2))
        return false
    }else if(newCount == 10){
        textField.text = addingCharacter ? currentText + "-\(string)" : String(currentText.dropLast(2))
        return false
    }

    if(newCount > 14){
        return false
    }

    return true
}

I use this format X (XXX) XXX XX XX it is work in Turkey,

I use it with TableView with Swift 4

func formatToPhoneNumber(withPhoneTextField: UITextField, tableTextField: UITextField, range: NSRange, string: String) -> Bool {

    if (tableTextField == withPhoneTextField) {

        let newString = (tableTextField.text! as NSString).replacingCharacters(in: range, with: string)
        let components = newString.components(separatedBy: NSCharacterSet.decimalDigits.inverted)

        let decimalString = components.joined(separator: "") as NSString
        let length = decimalString.length
        let hasLeadingOne = length > 0 && decimalString.character(at: 0) == (1 as unichar)

        if length == 0 || (length > 11 && !hasLeadingOne) || length > 12 {
            let newLength = (tableTextField.text! as NSString).length + (string as NSString).length - range.length as Int

            return (newLength > 11) ? false : true
        }

        var index = 0 as Int
        let formattedString = NSMutableString()

        if hasLeadingOne {
            formattedString.append("1 ")
            index += 1
        }

        if (length - index) > 1{
            let zeroNumber = decimalString.substring(with: NSMakeRange(index, 1))
            formattedString.appendFormat("%@ ", zeroNumber)
            index += 1
        }

        if (length - index) > 3 {
            let areaCode = decimalString.substring(with: NSMakeRange(index, 3))
            formattedString.appendFormat("(%@) ", areaCode)
            index += 3
        }

        if length - index > 3 {
            let prefix = decimalString.substring(with: NSMakeRange(index, 3))
            formattedString.appendFormat("%@ ", prefix)
            index += 3
        }

        if (length - index) > 3{
            let prefix = decimalString.substring(with: NSMakeRange(index, 2))
            formattedString.appendFormat("%@ ", prefix)
            index += 2
        }

        let remainder = decimalString.substring(from: index)
        formattedString.append(remainder)
        tableTextField.text = formattedString as String

        return false
    } else {
        return true
    }
}

and you can call this func in

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

}

in any indexPath that your text field in it

for example my textfield in indexPath number 1 so the code will be

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

    if indexPath.row == 1 {

        let phoneTextField = textField

        return formatToPhoneNumber(withPhoneTextField: phoneTextField, tableTextField: textField, range: range, string: string)

    }
}
Related