web-dev-qa-db-fra.com

UITextField pour numéro de téléphone

Je me demandais comment formater le champ textField que j'utilise pour un numéro de téléphone (par exemple, la page "Ajouter un nouveau contact" de l'iPhone. Lorsque j'entre dans un nouveau téléphone portable, par exemple, il est au format 1236890987 (123 ) 689-0987.) Le clavier est déjà défini comme pavé numérique.

47

Voici ma solution .. fonctionne très bien! Formate le numéro de téléphone en temps réel. Remarque: Ceci concerne les numéros de téléphone à 10 chiffres. Et actuellement, il le formate automatiquement comme (xxx) xxx-xxxx .. Ajustez à ravir votre coeur.

Tout d'abord, dans votre shouldChangeCharactersInRange, vous souhaitez rassembler la chaîne entière du champ de texte du téléphone et la transmettre à la fonction de validation/formatage.

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

Et voici où le numéro de téléphone est formaté. La regex pourrait probablement être nettoyée un peu. Mais j'ai testé ce code pendant un moment et semble passer toutes les cloches. Notez que nous utilisons également cette fonction pour supprimer un numéro du numéro de téléphone. Cela fonctionne un peu plus facilement ici, car nous avons déjà supprimé tous les autres chiffres.

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

Voici comment vous pouvez le faire dans 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

Réponse mise à jour de Vikzilla pour 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

Cela fait deux heures que je me bats avec ça. 

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

J'espère que quelqu'un peut contribuer.

10
Romeo

La fonction ci-dessous applique le format (999)333-5555 sur le champ de texte:

(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

Voici ma prise de celui-ci. Ce qui est proche de ce que fait Apple dans l’application Téléphone et Contacts (du moins lorsque votre région est définie sur États-Unis, je ne suis pas sûr si le comportement change par région).

J'étais particulièrement intéressé par le formatage jusqu'à 1 (123) 123-1234 et par la prise en charge de nombres plus longs sans formatage. Il y a aussi un bogue dans la vérification de range.length == 1 (pour delete/backspace) dans les autres solutions qui empêche un utilisateur de sélectionner la chaîne entière ou une partie de celle-ci et en appuyant sur la touche delete/backspace, ce qui résout ce problème.

Certains comportements étranges se produisent lorsque vous commencez à sélectionner une plage au milieu et à modifier, où le curseur se termine toujours à la fin de la chaîne en raison de la définition de la valeur des champs de texte. Je ne suis pas sûr de savoir comment repositionner le curseur dans une UITextField, je suppose que Apple utilise réellement une UITextView dans les applications Contacts et Téléphone, car elles maintiennent la position du curseur tout en effectuant ce formatage en ligne, elles semblent gérer toutes les petites nuances! Je souhaite qu'ils nous donnent juste ceci hors de la boîte.

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

Cette solution fonctionne parfaitement pour les numéros d'Amérique du Nord sans le préfixe international (+1) et sans extension. Le numéro sera au format "(212) 555-1234". Il va pré-taper le ")" et le "-", mais sera également supprimé correctement. 

Voici le -textField:shouldChangeCharactersInRange:replacementString que votre délégué de champ de texte doit implémenter:

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

Vous pouvez appeler cette méthode chaque fois que vous devez mettre à jour votre 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(encodedOffset: index)
            let patternCharacter = pattern[stringIndex]
            guard patternCharacter != replacmentCharacter else { continue }
            pureNumber.insert(patternCharacter, at: stringIndex)
        }
        return pureNumber
    }
}

Exemple: 

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

Réponse mise à jour pour Swift 2.0 de 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
}

A travaillé excelente pour moi, espérons que cela fonctionne pour vous aussi :) 

4
freaklix

Swift 4 (et sans NSString)

pour le format + X (XXX) XXX-XXXX ou + X (XXX) XXX-XX-XX Mis à jour et légèrement

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

Vous pouvez ajouter un numéro de téléphone tel que 000-000-0000 (10 chiffres)… .. Veuillez vous référer à ce code.

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

Ma solution pour le format + X (XXX) XXX-XXXX. (Rapide)

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

Voici mon code Swift 2 légèrement localisé du point de vue du Royaume-Uni.

Il formatera:

+11234567890 as +1 (123) 456 7890

Au +33123456789 au +33 1 23 45 67 89

+441234123456 comme +44 1234 123456 (ceci a été localisé plus loin que 01234 123456) car je n'ai pas besoin de voir l'indicatif de pays pour les numéros britanniques.

Appeler comme suit:

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

var formattedNo = formatInternationalPhoneNo("+11234567890")

Si vous avez d'autres codes de pays et formats ou améliorations du code, veuillez me le faire savoir.

Prendre plaisir.

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

Vous pouvez utiliser cette bibliothèque https://github.com/luximetr/AnyFormatKit

Exemple 

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

Il suffit de définir votre textField sur textInputController pour formater le texte avec le motif que vous avez défini.

Ou 

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

pour le format chaîne complète

1
iOS Developer

Malheureusement, vous devez le faire vous-même. L'application de contact utilise des API non documentées. Pour une raison quelconque, l’attachement de formateurs d’entrée à des champs de texte n’est pas exposé sur l’iPhone comme sur un Mac. N'hésitez pas à déposer un rapport de bogue d'amélioration de fonctionnalité.

1
Ramin

Voici ma solution pour le format de téléphone 05xx xxx xxxx. Au début je mis 

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

Il couvre également les cas de copier/coller pour la position du curseur.

Peut-être que cela aide quelqu'un pour différents formats.

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

J'espère que ce que je vais dire sera utile pour les nouvelles personnes programmant sur iOS, comme je le suis. J'ai fait ce que zingle-dingle suggère (merci beaucoup!). Pour aider les nouveaux, le code plus ce que je vais énumérer pourrait vous aider ... 1. vous devez ajouter UITextFieldDelegate sur le fichier d'en-tête. 2. UITextField doit lier le délégué à la vue, dans mon cas l'UIViewController, qui est le fichier d'en-tête. 3. UITextField doit être installé, cela signifie que votre_fichier.delegate = self, dans le fichier ".m". 

1

https://github.com/chebur/CHRTextFieldFormatter fonctionne comme un charme.

Copier/coller depuis la page d'utilisation:

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

Aussi rapide:

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

Réponse mise à jour de "iOS Unit" pour Swift 3 au format + 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

vous devez faire cela manuellement. prenez une notification de textField et vérifiez la longueur du champ text et formatez-le en fonction du pays . en cas de problème, faites le moi savoir Je l'ai fait

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

J'ai une solution à cela, mais il y a un inconvénient, voyez si vous pouvez le modifier et l'utiliser. En utilisant cela, vous pouvez limiter le numéro de téléphone à 10 chiffres et le formater selon le format américain.

#define MAX_LENGTH 10

Implémentez-le dans la méthode UITextField Delegate

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

C'est ma solution en utilisant Swift 4 pour formater un certain nombre de 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
}
0
JP Aquino