it-roy-ru.com

UITextField для номера телефона

Мне было интересно, как я могу отформатировать текстовое поле, которое я использую для телефонного номера (например, как страницу «Добавить новый контакт» на iPhone. Когда я вхожу в новый мобильный телефон, например, 1236890987, он форматирует его как (123 ) 689-0987.) У меня уже есть клавиатура в качестве цифровой клавиатуры.

47

Вот мое решение .. отлично работает! Форматирует номер телефона в режиме реального времени. Примечание: это для 10-значных телефонных номеров. И в настоящее время он автоматически форматирует его как (ххх) ххх-хххх .. твик к вашему сердцу восторг.

Сначала в вашей shouldChangeCharactersInRange вы хотите собрать всю строку для текстового поля телефона и передать ее в функцию проверки/форматирования.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* totalString = [NSString stringWithFormat:@"%@%@",textField.text,string];

// if it's the phone number textfield format it.
if(textField.tag==102 ) {
    if (range.length == 1) {
        // Delete button was hit.. so tell the method to delete the last char.
        textField.text = [self formatPhoneNumber:totalString deleteLastChar:YES];
    } else {
        textField.text = [self formatPhoneNumber:totalString deleteLastChar:NO ];
    }
    return false;
}

return YES; 
}

И вот где номер телефона отформатирован. Регулярное выражение, возможно, можно немного убрать. Но я тестировал этот код некоторое время и, кажется, прошел все звонки. Обратите внимание, что мы также используем эту функцию, чтобы удалить номер в номере телефона. Работает здесь немного проще, потому что мы уже удалили все остальные не цифры.

 -(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar {
if(simpleNumber.length==0) return @"";
// use regex to remove non-digits(including spaces) so we are left with just the numbers 
NSError *error = NULL;
 NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[\\s-\\(\\)]" options:NSRegularExpressionCaseInsensitive error:&error];
 simpleNumber = [regex stringByReplacingMatchesInString:simpleNumber options:0 range:NSMakeRange(0, [simpleNumber length]) withTemplate:@""];

// check if the number is to long
if(simpleNumber.length>10) {
    // remove last extra chars.
    simpleNumber = [simpleNumber substringToIndex:10];
}

if(deleteLastChar) {
    // should we delete the last digit?
    simpleNumber = [simpleNumber substringToIndex:[simpleNumber length] - 1];
}

// 123 456 7890
// format the number.. if it's less then 7 digits.. then use this regex.
if(simpleNumber.length<7)
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:@"(\\d{3})(\\d+)"
                                                           withString:@"($1) $2"
                                                              options:NSRegularExpressionSearch
                                                                range:NSMakeRange(0, [simpleNumber length])];

else   // else do this one..
    simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:@"(\\d{3})(\\d{3})(\\d+)"
                                                           withString:@"($1) $2-$3"
                                                              options:NSRegularExpressionSearch
                                                                range:NSMakeRange(0, [simpleNumber length])];
return simpleNumber;
}
67
zingle-dingle

Вот как вы можете сделать это в Swift 4:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    if (textField == phoneTextField) {
        let newString = (textField.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 > 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
    }
}
33
vikzilla

Обновленный ответ от Vikzilla для 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
    }
}
12
EPage_Ed

Я боролся с этим в течение нескольких часов, вот что у меня есть: 

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
     {
    NSUInteger currentLength = textField.text.length;
    NSCharacterSet *numbers = [NSCharacterSet decimalDigitCharacterSet];        

    if (range.length == 1) {
        return YES;
    }


    if ([numbers characterIsMember:[string characterAtIndex:0]]) {


        if ( currentLength == 3 ) 
        {

            if (range.length != 1) 
            {

                NSString *firstThreeDigits = [textField.text substringWithRange:NSMakeRange(0, 3)];

                NSString *updatedText;

                if ([string isEqualToString:@"-"]) 
                {
                    updatedText = [NSString stringWithFormat:@"%@",firstThreeDigits];
                }

                else 
                {
                    updatedText = [NSString stringWithFormat:@"%@-",firstThreeDigits];
                }

                [textField setText:updatedText];
            }           
        }

        else if ( currentLength > 3 && currentLength < 8 ) 
        {

            if ( range.length != 1 ) 
            {

                NSString *firstThree = [textField.text substringWithRange:NSMakeRange(0, 3)];
                NSString *dash = [textField.text substringWithRange:NSMakeRange(3, 1)];

                NSUInteger newLenght = range.location - 4;

                NSString *nextDigits = [textField.text substringWithRange:NSMakeRange(4, newLenght)];

                NSString *updatedText = [NSString stringWithFormat:@"%@%@%@",firstThree,dash,nextDigits];

                [textField setText:updatedText];

            }

        }

        else if ( currentLength == 8 ) 
        {

            if ( range.length != 1 ) 
            {
                NSString *areaCode = [textField.text substringWithRange:NSMakeRange(0, 3)];

                NSString *firstThree = [textField.text substringWithRange:NSMakeRange(4, 3)];

                NSString *nextDigit = [textField.text substringWithRange:NSMakeRange(7, 1)];

                [textField setText:[NSString stringWithFormat:@"(%@) %@-%@",areaCode,firstThree,nextDigit]];
            }

        }
    }

    else {
        return NO;
    }

    return YES;
}

Я надеюсь, что кто-то может внести свой вклад.

10
Romeo

Функция ниже обеспечивает формат (999)333-5555 для textField:

Swift 3:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if (textField == self.phone){
            let newString = (textField.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 > 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
        }
    }
9
Rao

Вот мое мнение об этом. Что близко к тому, что Apple делает в приложении «Телефон и контакты» (по крайней мере, если для вашего региона установлено значение «США», я не уверен, что поведение меняется в каждом регионе).

Меня особенно интересовало форматирование до 1 (123) 123-1234 и поддержка более длинных чисел без форматирования. Существует также ошибка в простой проверке range.length == 1 (для удаления/возврата) в других решениях, которая не позволяет пользователю выбрать всю строку или ее часть и нажать клавишу удаления/возврата, это решает эту ситуацию.

Есть некоторые странные поведения, которые возникают, когда вы начинаете выбирать диапазон в середине и редактировать, где курсор всегда заканчивается концом строки из-за установки значения текстовых полей. Я не уверен, как изменить положение курсора в UITextField, я предполагаю, что Apple фактически использует UITextView в приложениях «Контакты» и «Телефон», поскольку они поддерживают положение курсора, а при этом встроенном форматировании они, кажется, обрабатывают все мелкие нюансы! Я хотел бы, чтобы они просто дали нам это из коробки.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSMutableString *newString = [NSMutableString stringWithString:textField.text];
    [newString replaceCharactersInRange:range withString:string];
    NSString *phoneNumberString = [self formattedPhoneNumber:newString];

    if (range.length >= 1) { // backspace/delete
        if (phoneNumberString.length > 1) {
            // the way we format the number it is possible that when the user presses backspace they are not deleting the last number
            // in the string, so we need to check if the last character is a number, if it isn't we need to delete everything after the
            // last number in the string
            unichar lastChar = [phoneNumberString characterAtIndex:phoneNumberString.length-1];
            NSCharacterSet *numberCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"1234567890#*"];
            if (![numberCharacterSet characterIsMember:lastChar]) {
                NSRange numberRange = [phoneNumberString rangeOfCharacterFromSet:numberCharacterSet options:NSBackwardsSearch];
                phoneNumberString = [phoneNumberString substringToIndex:numberRange.location+1];
            }
        }
    }

    textField.text = phoneNumberString;

    return NO;
}

- (NSString *)formattedPhoneNumber:(NSString *)string {
    NSString *formattedPhoneNumber = @"";
    NSCharacterSet *numberCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"1234567890#*+"];

    NSRange pauseRange = [string rangeOfString:@","];
    NSRange waitRange = [string rangeOfString:@";"];


    NSString *numberStringToFormat = nil;
    NSString *numberStringToAppend = @"";
    if (pauseRange.location != NSNotFound || waitRange.location != NSNotFound) {
        NSString *choppedString = [string substringToIndex:MIN(pauseRange.location, waitRange.location)];
        numberStringToFormat = [[choppedString componentsSeparatedByCharactersInSet:[numberCharacterSet invertedSet]] componentsJoinedByString:@""];
        numberStringToAppend = [string substringFromIndex:MIN(pauseRange.location, waitRange.location)];
    } else {
        numberStringToFormat = [[string componentsSeparatedByCharactersInSet:[numberCharacterSet invertedSet]] componentsJoinedByString:@""];
    }

    if ([numberStringToFormat hasPrefix:@"0"] || [numberStringToFormat hasPrefix:@"11"]) {
        // numbers starting with 0 and 11 should not be formatted
        formattedPhoneNumber = numberStringToFormat;

    } else if ([numberStringToFormat hasPrefix:@"1"]) {
        if (numberStringToFormat.length <= 1) {
            // 1
            formattedPhoneNumber = numberStringToFormat;
        } else if (numberStringToFormat.length <= 4) {
            // 1 (234)
            NSString *areaCode = [numberStringToFormat substringFromIndex:1];
            if (areaCode.length < 3) {
                formattedPhoneNumber = [NSString stringWithFormat:@"1 (%@",
                                        [numberStringToFormat substringFromIndex:1]]; // 1 (XXX)
            } else {
                formattedPhoneNumber = [NSString stringWithFormat:@"1 (%@) ",
                                        [numberStringToFormat substringFromIndex:1]]; // 1 (XXX)
            }

        } else if (numberStringToFormat.length <= 7) {
            // 1 (234) 123
            formattedPhoneNumber = [NSString stringWithFormat:@"1 (%@) %@",
                                    [numberStringToFormat substringWithRange:NSMakeRange(1, 3)], //1 (XXX) 123
                                    [numberStringToFormat substringFromIndex:4]]; // 1 (234) XXX

        } else if (numberStringToFormat.length <= 11) {
            // 1 (123) 123-1234
            formattedPhoneNumber = [NSString stringWithFormat:@"1 (%@) %@-%@",
                                    [numberStringToFormat substringWithRange:NSMakeRange(1, 3)], //1 (XXX) 123
                                    [numberStringToFormat substringWithRange:NSMakeRange(4, 3)], //1 (234) XXX-1234
                                    [numberStringToFormat substringFromIndex:7]]; // 1 (234) 123-XXXX
        } else {
            // 1123456789012....
            formattedPhoneNumber = numberStringToFormat;
        }
    } else {
        if (numberStringToFormat.length <= 3) {
            // 123
            formattedPhoneNumber = numberStringToFormat;
        } else if (numberStringToFormat.length <= 7) {
            // 123-1234
            formattedPhoneNumber = [NSString stringWithFormat:@"%@-%@",
                                    [numberStringToFormat substringToIndex:3], // XXX-1234
                                    [numberStringToFormat substringFromIndex:3]]; // 123-XXXX
        } else if (numberStringToFormat.length <= 10) {
            // (123) 123-1234
            formattedPhoneNumber = [NSString stringWithFormat:@"(%@) %@-%@",
                                    [numberStringToFormat substringToIndex:3], // (XXX) 123-1234
                                    [numberStringToFormat substringWithRange:NSMakeRange(3, 3)], // (123) XXX-1234
                                    [numberStringToFormat substringFromIndex:6]]; // (123) 123-XXXX

        } else {
            // 123456789012....
            formattedPhoneNumber = numberStringToFormat;
        }
    }

    if (numberStringToAppend.length > 0) {
        formattedPhoneNumber = [NSString stringWithFormat:@"%@%@", formattedPhoneNumber, numberStringToAppend];
    }

    return formattedPhoneNumber;
}
6
Chris Wagner

Это решение отлично работает для номеров в Северной Америке без префикса международного набора (+1) и без расширения. Номер будет отформатирован как "(212) 555-1234". Он предварительно введет «)» и «-», но также удалит правильно. 

Вот -textField:shouldChangeCharactersInRange:replacementString, который должен реализовать ваш делегат текстового поля:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == self.myPhoneTextField) {
        NSString *newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
        BOOL deleting = [newText length] < [textField.text length];

        NSString *stripppedNumber = [newText stringByReplacingOccurrencesOfString:@"[^0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [newText length])];
        NSUInteger digits = [stripppedNumber length];

        if (digits > 10)
            stripppedNumber = [stripppedNumber substringToIndex:10];

        UITextRange *selectedRange = [textField selectedTextRange];
        NSInteger oldLength = [textField.text length];

        if (digits == 0)
            textField.text = @"";
        else if (digits < 3 || (digits == 3 && deleting))
            textField.text = [NSString stringWithFormat:@"(%@", stripppedNumber];
        else if (digits < 6 || (digits == 6 && deleting))
            textField.text = [NSString stringWithFormat:@"(%@) %@", [stripppedNumber substringToIndex:3], [stripppedNumber substringFromIndex:3]];
        else
            textField.text = [NSString stringWithFormat:@"(%@) %@-%@", [stripppedNumber substringToIndex:3], [stripppedNumber substringWithRange:NSMakeRange(3, 3)], [stripppedNumber substringFromIndex:6]];

        UITextPosition *newPosition = [textField positionFromPosition:selectedRange.start offset:[textField.text length] - oldLength];
        UITextRange *newRange = [textField textRangeFromPosition:newPosition toPosition:newPosition];
        [textField setSelectedTextRange:newRange];

        return NO;
    }

    return YES;
}
5
Frank Schmitt

Вы можете вызывать этот метод всякий раз, когда вам нужно обновить текстовое поле:

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
    }
}

Пример: 

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

Обновленный ответ для Swift 2.0 от Vikzilla:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    sendButton.enabled = true
    let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
    let components = newString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)

    let decimalString : String = components.joinWithSeparator("")
    let length = decimalString.characters.count
    let decimalStr = decimalString as NSString
    let hasLeadingOne = length > 0 && decimalStr.characterAtIndex(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.appendString("1 ")
        index += 1
    }
    if (length - index) > 3
    {
        let areaCode = decimalStr.substringWithRange(NSMakeRange(index, 3))
        formattedString.appendFormat("(%@)", areaCode)
        index += 3
    }
    if length - index > 3
    {
        let prefix = decimalStr.substringWithRange(NSMakeRange(index, 3))
        formattedString.appendFormat("%@-", prefix)
        index += 3
    }

    let remainder = decimalStr.substringFromIndex(index)
    formattedString.appendString(remainder)
    textField.text = formattedString as String
    return false
}

Работал отлично для меня, надеюсь, это работает и для вас :) 

4
freaklix

Swift 4 (и без NSString)

для формата + X (XXX) XXX-XXXX или + X (XXX) XXX-XX-XX Обновлено и немного

class ViewController: UIViewController, UITextFieldDelegate {

    var myPhoneNumber = String()

    @IBOutlet weak var phoneTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        phoneTextField.delegate = self
        phoneTextField.keyboardType = .phonePad
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {
        if (textField == self.phoneTextField) && textField.text == ""{
            textField.text = "+7(" //your country code default
        }
    }

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

        if textField == phoneTextField {
            let res = phoneMask(phoneTextField: phoneTextField, textField: textField, range, string)
            myPhoneNumber = res.phoneNumber != "" ? "+\(res.phoneNumber)" : ""
            print("Phone - \(myPhoneNumber)  MaskPhone=\(res.maskPhoneNumber)")
            if (res.phoneNumber.count == 11) || (res.phoneNumber.count == 0) {
                //phone number entered or completely cleared
                print("EDIT END: Phone = \(myPhoneNumber)  MaskPhone = \(res.maskPhoneNumber)")
            }
            return res.result
        }
        return true
    }
}

extension UITextFieldDelegate {
    func phoneMask(phoneTextField: UITextField, textField: UITextField, _ range: NSRange, _ string: String) -> (result: Bool, phoneNumber: String, maskPhoneNumber: String) {
        let oldString = textField.text!
        let newString = oldString.replacingCharacters(in: Range(range, in: oldString)!, with: string)
        //in numString only Numeric characters
        let components = newString.components(separatedBy: CharacterSet.decimalDigits.inverted)
        let numString = components.joined(separator: "")

        let length = numString.count
        let maxCharInPhone = 11

        if newString.count < oldString.count { //backspace to work
            if newString.count <= 2 { //if now "+7(" and Push backspace
                phoneTextField.text = ""
                return (false, "", "")
            } else {
                return (true, numString, newString) //will not in the process backspace
            }
        }

        if length > maxCharInPhone { // input is complete, do not add characters
            return (false, numString, newString)
        }
        var indexStart, indexEnd: String.Index
        var maskString = "", template = ""
        var endOffset = 0

        if newString == "+" { // allow add "+" if first Char
            maskString += "+"
        }
        //format +X(XXX)XXX-XXXX
        if length > 0 {
            maskString += "+"
            indexStart = numString.index(numString.startIndex, offsetBy: 0)
            indexEnd = numString.index(numString.startIndex, offsetBy: 1)
            maskString += String(numString[indexStart..<indexEnd]) + "("
        }
        if length > 1 {
            endOffset = 4
            template = ")"
            if length < 4 {
                endOffset = length
                template = ""
            }
            indexStart = numString.index(numString.startIndex, offsetBy: 1)
            indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
            maskString += String(numString[indexStart..<indexEnd]) + template
        }
        if length > 4 {
            endOffset = 7
            template = "-"
            if length < 7 {
                endOffset = length
                template = ""
            }
            indexStart = numString.index(numString.startIndex, offsetBy: 4)
            indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
            maskString += String(numString[indexStart..<indexEnd]) + template
        }
        var nIndex: Int; nIndex = 7
//            //format +X(XXX)XXX-XX-XX  -> if need uncoment
//            nIndex = 9
//
//            if length > 7 {
//                endOffset = 9
//                template = "-"
//                if length < 9 {
//                    endOffset = length
//                    template = ""
//                }
//                indexStart = numString.index(numString.startIndex, offsetBy: 7)
//                indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
//                maskString += String(numString[indexStart..<indexEnd]) + template
//            }
        if length > nIndex {
            indexStart = numString.index(numString.startIndex, offsetBy: nIndex)
            indexEnd = numString.index(numString.startIndex, offsetBy: length)
            maskString += String(numString[indexStart..<indexEnd])
        }
        phoneTextField.text = maskString
        if length == maxCharInPhone {
            //dimiss kayboard
            phoneTextField.endEditing(true)
            return (false, numString, newString)
        }
        return (false, numString, newString)
    }
}
3
flowGlen

Вы можете добавить номер телефона, например, 000-000-0000 (10-значный) . Пожалуйста, используйте этот код.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (textField==Phone_TXT)
    {
        if (range.location == 12)
        {
            return NO;
        }

        // Backspace
        if ([string length] == 0)
            return YES;

        if ((range.location == 3) || (range.location == 7))
        {

            NSString *str    = [NSString stringWithFormat:@"%@-",textField.text];
            textField.text   = str;
        }

        return YES;
    }
}
3
Kaushik Movaliya

Мое решение для формата + X (XXX) XXX-XXXX. (Swift)

func textFieldDidBeginEditing(textField: UITextField) {
    if (textField == self.mobileField) {
        textField.text = "+"
    }
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if (textField == self.mobileField) {
        let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

        if (newString.characters.count < textField.text?.characters.count && newString.characters.count >= 1) {
            return true                                                         // return true for backspace to work
        } else if (newString.characters.count < 1) {
            return false;                        // deleting "+" makes no sence
        }
        if (newString.characters.count > 17 ) {
           return false;
        }

        let components = newString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)

        let decimalString = components.joinWithSeparator("") as NSString
        let length = decimalString.length

        var index = 0
        let formattedString = NSMutableString()
        formattedString.appendString("+")

        if (length >= 1) {
            let countryCode = decimalString.substringWithRange(NSMakeRange(0, 1))
            formattedString.appendString(countryCode)
            index += 1
        }

        if (length > 1) {
            var rangeLength = 3
            if (length < 4) {
                rangeLength = length - 1
            }
            let operatorCode = decimalString.substringWithRange(NSMakeRange(1, rangeLength))
            formattedString.appendFormat(" (%@) ", operatorCode)
            index += operatorCode.characters.count
        }

        if (length > 4) {
            var rangeLength = 3
            if (length < 7) {
                rangeLength = length - 4
            }
            let prefix = decimalString.substringWithRange(NSMakeRange(4, rangeLength))
            formattedString.appendFormat("%@-", prefix)
            index += prefix.characters.count
        }

        if (index < length) {
            let remainder = decimalString.substringFromIndex(index)
            formattedString.appendString(remainder)
        }

        textField.text = formattedString as String

        if (newString.characters.count == 17) {
            textField.resignFirstResponder()
        }

        return false
    }

    return true
}
3
iOS Unit

Вот мой код Swift 2 от немного локализованного с точки зрения Великобритании.

Это отформатирует:

+11234567890 как +1 (123) 456 7890

+33123456789 как +33 1 23 45 67 89

+441234123456 как +44 1234 123456 (это было дополнительно локализовано как 01234 123456), потому что мне не нужно видеть код страны для номеров Великобритании.

Звоните следующим образом:

initInternationalPhoneFormats() //this just needs to be done once

var formattedNo = formatInternationalPhoneNo("+11234567890")

Если у вас есть другие коды стран, форматы или улучшения кода, пожалуйста, дайте мне знать.

Наслаждаться.

import Cocoa

extension String
{
    //extension from http://stackoverflow.com/questions/24092884/get-nth-character-of-a-string-in-Swift-programming-language

    subscript (i: Int) -> Character
    {
        return self[self.startIndex.advancedBy(i)]
    }

}

var phoneNoFormat = [String : String]()
var localCountryCode: String? = "+44"

func initInternationalPhoneFormats() 
{
    if phoneNoFormat.count == 0
    {
         phoneNoFormat["0"] = "+44 #### ######" //local no (UK)
         phoneNoFormat["02"] = "+44 ## #### #####" //local no (UK) London

         phoneNoFormat["+1"] = "+# (###) ###-####" //US and Canada

         phoneNoFormat["+234"] = "+## # ### ####" //Nigeria
         phoneNoFormat["+2348"] = "+## ### ### ####" //Nigeria Mobile

         phoneNoFormat["+31"] = "+## ### ## ## ##" //Netherlands
         phoneNoFormat["+316"] = "+## # ## ## ## ##" //Netherlands Mobile
         phoneNoFormat["+33"] = "+## # ## ## ## ##" //France
         phoneNoFormat["+39"] = "+## ## ########" //Italy
         phoneNoFormat["+392"] = "+## #### #####" //Italy
         phoneNoFormat["+393"] = "+## ### #######" //Italy

         phoneNoFormat["+44"] = "+## #### ######" //United Kingdom
         phoneNoFormat["+442"] = "+## ## #### #####" //United Kingdom London

         phoneNoFormat["+51"] = "+## # ### ####" //Peru
         phoneNoFormat["+519"] = "+## ### ### ###" //Peru Mobile
         phoneNoFormat["+54"] = "+## ### ### ####" //Argentina
         phoneNoFormat["+541"] = "+## ## #### ####" //Argentina
         phoneNoFormat["+549"] = "+## # ### ### ####" //Argentina
         phoneNoFormat["+55"] = "+## (##) ####-####" //Brazil
         phoneNoFormat["+551"] = "+## (##) ####-###" //Brazil Mobile?

         phoneNoFormat["+60"] = "+## # #### ####" //Malaysia
         phoneNoFormat["+6012"] = "+## ## ### ####" //Malaysia Mobile
         phoneNoFormat["+607"] = "+## # ### ####" //Malaysia?
         phoneNoFormat["+61"] = "+## # #### ####" //Australia
         phoneNoFormat["+614"] = "+## ### ### ###" //Australia Mobile
         phoneNoFormat["+62"] = "+## ## #######" //Indonesia
         phoneNoFormat["+628"] = "+## ### ######" //Indonesia Mobile
         phoneNoFormat["+65"] = "+## #### ####" //Singapore

         phoneNoFormat["+90"] = "+## (###) ### ## ##" //Turkey
     }
 }

 func getDiallingCode(phoneNo: String) -> String
 {
     var countryCode = phoneNo
     while countryCode.characters.count > 0 && phoneNoFormat[countryCode] == nil
     {
         countryCode = String(countryCode.characters.dropLast())
     }
     if countryCode == "0"
     {
         return localCountryCode!
     }
     return countryCode
 }


 func formatInternationalPhoneNo(fullPhoneNo: String, localisePhoneNo: Bool = true) -> String
 {
     if fullPhoneNo == ""
     {
         return ""
     }
     initInternationalPhoneFormats()

     let diallingCode = getDiallingCode(fullPhoneNo)

     let localPhoneNo = fullPhoneNo.stringByReplacingOccurrencesOfString(diallingCode, withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)

     var filteredPhoneNo = (localPhoneNo.characters.filter{["0","1","2","3","4","5","6","7","8","9"].contains($0)})
     if filteredPhoneNo[0] == "0"
     {
         filteredPhoneNo.removeFirst()
     }

     let phoneNo:String = diallingCode + String(filteredPhoneNo)

     if let format = phoneNoFormat[diallingCode]
     {
         let formatLength = format.characters.count
         var formattedPhoneNo = [Character]()
         var formatPos = 0
         for char in phoneNo.characters
         {
             while formatPos < formatLength && format[formatPos] != "#" && format[formatPos] != "+"
             {
                 formattedPhoneNo.append(format[formatPos])
                 formatPos++
             }

             if formatPos < formatLength
             {
                 formattedPhoneNo.append(char)
                 formatPos++
             }
             else
             {
                 break
             }
         }
         if localisePhoneNo,
             let localCode = localCountryCode
         {
             return String(formattedPhoneNo).stringByReplacingOccurrencesOfString(localCode + " ", withString: "0", options: NSStringCompareOptions.LiteralSearch, range: nil) //US users need to remove the extra 0
         }
         return String(formattedPhoneNo)
     }
     return String(filteredPhoneNo)
 }
2
iphaaw

Вы можете использовать эту библиотеку https://github.com/luximetr/AnyFormatKit

Пример 

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

Просто установите ваш textField на этот textInputController, и он будет форматировать текст с установленным вами шаблоном.

Или же 

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

для форматирования полной строки

1
iOS Developer

К сожалению, вы должны сделать это самостоятельно. Приложение контактов использует недокументированные API. По какой-то причине присоединение форматеров ввода к текстовым полям не отображается на iPhone так, как на Mac. Не стесняйтесь подать отчет об ошибке улучшения функции.

1
Ramin

Вот мое решение для телефона формата 05xx xxx xxxx. В начале я установил 

phoneTextField.delegate = self
phoneTextField.text = "05" // I don't let user to change it.

Он также охватывает случаи копирования/вставки для позиции курсора.

Может быть, это помогает кому-то для разных форматов.

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

    if range.location == 0 || range.location == 1 {
        return false
    }

    var phone = (textField.text! as NSString).replacingCharacters(in: range, with: string)

    if phone.length > 13 {
        return false
    }

    phone = phone.replacingOccurrences(of: " ", with: "")
    if phone.characters.count > 7 {
        phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 4))
        phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 8))
    } else if phone.characters.count > 4 {
        phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 4))
    }

    let text = textField.text
    let stringToStart = text?.substring(to: (text?.index((text?.startIndex)!, offsetBy: range.location))!)

    let stringToStartCount = ((stringToStart?.components(separatedBy: " ").count)! > 1) ? (stringToStart?.components(separatedBy: " ").count)!-1 : 0

    var cursorIndex = range.location + string.length - stringToStartCount

    if cursorIndex > 7 {
        cursorIndex += 2
    } else if cursorIndex > 4 {
        cursorIndex += 1
    }

    textField.text = phone
    textField.selectedTextRange = textField.textRange(from: textField.position(from: textField.beginningOfDocument, offset: cursorIndex)!, to: textField.position(from: textField.beginningOfDocument, offset: cursorIndex)!)

    return false
}
1
Seref Bulbul

Надеюсь, то, что я собираюсь сказать, будет полезно для новых людей, программирующих на iOS, как и я. Я сделал то, что предлагает Zingle-Dingle (большое спасибо!). Чтобы помочь новым, вам может помочь код и то, что я перечислю .. 1. Вы должны добавить UITextFieldDelegate в заголовочный файл. 2. UITextField должен связать делегата с представлением, в моем случае UIViewController, который является файлом заголовка. 3. UITextField должен быть установлен, т. е. yourtextfile.delegate = self, в файле ".m". 

1
Carlos Duque Yemail

https://github.com/chebur/CHRTextFieldFormatter работает для меня как шарм.

Скопируйте/вставьте со страницы использования:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.phoneNumberFormatter = [[CHRTextFieldFormatter alloc] initWithTextField:self.phoneNumberTextField mask:[CHRPhoneNumberMask new]];
    self.cardNumberFormatter = [[CHRTextFieldFormatter alloc] initWithTextField:self.cardNumberTextField mask:[CHRCardNumberMask new]];
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == self.phoneNumberTextField) {
        return [self.phoneNumberFormatter textField:textField shouldChangeCharactersInRange:range replacementString:string];
    } else if (textField == self.cardNumberTextField) {
        return [self.cardNumberFormatter textField:textField shouldChangeCharactersInRange:range replacementString:string];
    } else {
        return YES;
    }
}

Также Свифт:

override func viewDidLoad() {
    super.viewDidLoad()
    self.phoneNumber.delegate = self
    self.phoneNumberFormatter = CHRTextFieldFormatter(textField: self.phoneNumber, mask:CHRPhoneNumberMask())
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if textField == self.phoneNumber {
        return self.phoneNumberFormatter.textField(textField, shouldChangeCharactersInRange: range, replacementString: string)
    }
    return true
}
1
user1232690

Обновленный ответ от «iOS Unit» для Swift 3 с форматом + X (XXX) XXX-XXXX:

func textFieldDidBeginEditing(_ textField: UITextField) {
        if (textField == self.phoneTextField) {
            textField.text = "+"
        }
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if (textField == self.phoneTextField) {
            let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)

            if (newString.characters.count < (textField.text?.characters.count)! && newString.characters.count >= 1) {
                return true                                                         // return true for backspace to work
            } else if (newString.characters.count < 1) {
                return false;                        // deleting "+" makes no sence
            }
            if (newString.characters.count > 17 ) {
                return false;
            }

            let components = newString.components(separatedBy: CharacterSet.decimalDigits.inverted)
            let decimalString = components.joined(separator: "") as NSString
            let length = decimalString.length

            var index = 0
            let formattedString = NSMutableString()
            formattedString.append("+")

            if (length >= 1) {
                let countryCode = decimalString.substring(with: NSMakeRange(0, 1))
                formattedString.append(countryCode)
                index += 1
            }

            if (length > 1) {
                var rangeLength = 3
                if (length < 4) {
                    rangeLength = length - 1
                }
                let operatorCode = decimalString.substring(with: NSMakeRange(1, rangeLength))
                formattedString.appendFormat(" (%@) ", operatorCode)
                index += operatorCode.characters.count
            }

            if (length > 4) {
                var rangeLength = 3
                if (length < 7) {
                    rangeLength = length - 4
                }
                let prefix = decimalString.substring(with: NSMakeRange(4, rangeLength))
                formattedString.appendFormat("%@-", prefix)
                index += prefix.characters.count
            }

            if (index < length) {
                let remainder = decimalString.substring(from: index)
                formattedString.append(remainder)
            }

            textField.text = formattedString as String

            if (newString.characters.count == 17) {
                textField.resignFirstResponder()
            }

            return false
        }

        return true
    }
1
Sergey Balashov

ты должен сделать это вручную. возьмите уведомление о textField и проверьте длину текста поля и отформатируйте его в соответствии со страной ........ если возникнут проблемы, дайте мне знать. Я сделал это

0
Sandeep Kumar
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

NSCharacterSet* validationSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSArray* components = [string componentsSeparatedByCharactersInSet:validationSet];

if ([components count] > 1) {
    return NO;
}

NSString* newString = [textField.text stringByReplacingCharactersInRange:range
                                                                 withString:string];

NSArray* validComponents = [newString componentsSeparatedByCharactersInSet:validationSet];

static const int localNumberMaxLength = 7;
static const int areaCodeMaxLength = 3;
static const int countryCodeMaxLength = 2;

newString = [validComponents componentsJoinedByString:@""];

if ([newString length] > localNumberMaxLength + areaCodeMaxLength + countryCodeMaxLength) {
    return NO;
}


NSLog(@"new string: %@", newString);

NSMutableString* resultString = [NSMutableString string];

NSInteger localNumberLength = MIN([newString length], localNumberMaxLength);

if (localNumberLength > 0) {
    NSString* number = [newString substringFromIndex:(int)[newString length] - localNumberLength];
    [resultString appendString:number];

    if ([resultString length] > 3) {
        [resultString insertString:@"-" atIndex:3];
    }
}

if ([newString length] > localNumberMaxLength) {
    NSInteger areaCodeLength = MIN((int)[newString length] - localNumberMaxLength, areaCodeMaxLength);
    NSRange areaRange = NSMakeRange((int)[newString length] - localNumberMaxLength - areaCodeLength, areaCodeLength);
    NSString* area = [newString substringWithRange:areaRange];

    area = [NSString stringWithFormat:@"(%@) ",area];

    [resultString insertString:area atIndex:0];
}

if ([newString length] > localNumberMaxLength + areaCodeMaxLength) {
    NSInteger countryCodeLength = MIN((int)[newString length] - localNumberMaxLength - areaCodeMaxLength, countryCodeMaxLength);
    NSRange countryCodeRange = NSMakeRange(0, countryCodeLength);
    NSString* countryCode = [newString substringWithRange:countryCodeRange];

    countryCode = [NSString stringWithFormat:@"+%@ ",countryCode];

    [resultString insertString:countryCode atIndex:0];
}

textField.text = resultString;
return NO;    

}

0
Alex_Burla

У меня есть решение для этого, но у него есть некоторый недостаток, посмотрите, можете ли вы его изменить и использовать. Используя это, вы можете ограничить номер телефона до 10 цифр и отформатировать его в соответствии с американским форматом.

#define MAX_LENGTH 10

Реализуйте это в методе делегата UITextField

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

{

 NSInteger insertDelta = string.length - range.length;

if (PhoneNumber_txt.text.length + insertDelta > MAX_LENGTH)
{
    return NO; // the new string would be longer than MAX_LENGTH
}
else {

    range.length = 3;
    range.location = 3;

    PhoneNumber_txt.text = [NSString stringWithFormat:@"(%@)%@-%@", [PhoneNumber_txt.text substringToIndex:3], [PhoneNumber_txt.text substringWithRange:range], [PhoneNumber_txt.text substringFromIndex:6]];
    return YES;
}
 }
0
Gaurav

Это мое решение с использованием Swift 4 для форматирования числа типа (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
}
0
JP Aquino