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

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

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

Сначала в вашем 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; } 

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

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if (textField == phoneTextField) { let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string) let components = newString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet) let decimalString = components.joinWithSeparator("") as NSString let length = decimalString.length let hasLeadingOne = length > 0 && decimalString.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 = decimalString.substringWithRange(NSMakeRange(index, 3)) formattedString.appendFormat("(%@)", areaCode) index += 3 } if length - index > 3 { let prefix = decimalString.substringWithRange(NSMakeRange(index, 3)) formattedString.appendFormat("%@-", prefix) index += 3 } let remainder = decimalString.substringFromIndex(index) formattedString.appendString(remainder) textField.text = formattedString as String return false } else { return true } } 

Обновленный ответ от 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 } } 

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

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

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

Ниже функция принудительно вводит формат (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 } } 

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

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

Есть некоторые странные поведения, которые возникают, когда вы начинаете выбирать диапазон в середине и редактировать, где курсор всегда заканчивается в конце строки из-за установки значения текстовых полей. Я не уверен, как переместить курсор в 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; } 

Это решение отлично подходит для североамериканских номеров без префикса международного набора (+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; } 

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

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

Вы можете добавить номер телефона, например 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; } } 

Мое решение для формата + X (XXX) XXX-XXXX. (СВИФТ)

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

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.. 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.. 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.. 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.. nIndex { indexStart = numString.index(numString.startIndex, offsetBy: nIndex) indexEnd = numString.index(numString.startIndex, offsetBy: length) maskString += String(numString[indexStart.. 

Вы можете вызвать этот метод всякий раз, когда вам нужно обновить 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 } } 

Пример:

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

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

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

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

Он будет форматировать:

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

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

+441234123456 as +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) } 

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 } 

Updated answer from “iOS Unit” for Swift 3 with 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 } 

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

I have a solution for this but it is having some drawback, see if you can modify and use it. By using this you can achieve both restrict phone number to 10 digit and format it as per US format.

 #define MAX_LENGTH 10 

Implement it in UITextField Delegate method

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

}

Here is my solution for 05xx xxx xxxx phone format. At the beginning I set

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

It also covers copy/paste cases for cursor position.

Maybe it helps someone for different 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 } 

You can use this library 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 

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

Или

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

for format full string

objective c solution for +X (XXX) XXX-XXXX format

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (textField == objCell.txtPhone) { NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; if (newString.length < ([textField.text length]) && newString.length >= 1) { return true; } else if (newString.length < 1) { return false; } if (newString.length > 15 ) { return false; } NSArray *components =[newString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; NSString *decimalString = [components componentsJoinedByString:@""]; NSUInteger length = decimalString.length; NSUInteger index = 0; NSMutableString *formattedString=[[NSMutableString alloc] init]; [formattedString appendString:@"+"]; if (length >= 1) { NSString *countryCode = [decimalString substringWithRange:NSMakeRange(0,1)]; [formattedString appendString:countryCode]; index += 1; } if (length > 1) { NSUInteger rangeLength = 3; if (length < 4) { rangeLength = length - 1; } NSString *operatorCode = [decimalString substringWithRange:NSMakeRange(1, rangeLength)]; [formattedString appendFormat:@"(%@)",operatorCode]; index += operatorCode.length; } if (length > 4) { NSUInteger rangeLength = 3; if (length < 7) { rangeLength = length - 4; } NSString *prefix = [decimalString substringWithRange:NSMakeRange(4, rangeLength)]; [formattedString appendFormat:@"%@-",prefix]; index += prefix.length; } if (index < length) { NSString *remainder = [decimalString substringFromIndex:index]; [formattedString appendString:remainder]; } textField.text = formattedString; if (newString.length == 15) { [textField resignFirstResponder]; } contactNumberAdded=decimalString; return false; } return YES; } 

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

I use it with TableView with Swift 4

 func formatToPhoneNumber(withPhoneTextField: UITextField, tableTextField: UITextField, range: NSRange, string: String) -> Bool { if (tableTextField == withPhoneTextField) { let newString = (tableTextField.text! as NSString).replacingCharacters(in: range, with: string) let components = newString.components(separatedBy: NSCharacterSet.decimalDigits.inverted) let decimalString = components.joined(separator: "") as NSString let length = decimalString.length let hasLeadingOne = length > 0 && decimalString.character(at: 0) == (1 as unichar) if length == 0 || (length > 11 && !hasLeadingOne) || length > 12 { let newLength = (tableTextField.text! as NSString).length + (string as NSString).length - range.length as Int return (newLength > 11) ? false : true } var index = 0 as Int let formattedString = NSMutableString() if hasLeadingOne { formattedString.append("1 ") index += 1 } if (length - index) > 1{ let zeroNumber = decimalString.substring(with: NSMakeRange(index, 1)) formattedString.appendFormat("%@ ", zeroNumber) index += 1 } if (length - index) > 3 { let areaCode = decimalString.substring(with: NSMakeRange(index, 3)) formattedString.appendFormat("(%@) ", areaCode) index += 3 } if length - index > 3 { let prefix = decimalString.substring(with: NSMakeRange(index, 3)) formattedString.appendFormat("%@ ", prefix) index += 3 } if (length - index) > 3{ let prefix = decimalString.substring(with: NSMakeRange(index, 2)) formattedString.appendFormat("%@ ", prefix) index += 2 } let remainder = decimalString.substring(from: index) formattedString.append(remainder) tableTextField.text = formattedString as String return false } else { return true } } 

and you can call this func in

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

in any indexPath that your text field in it

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

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String, indexPath: IndexPath) -> Bool { if indexPath.row == 1 { let phoneTextField = textField return formatToPhoneNumber(withPhoneTextField: phoneTextField, tableTextField: textField, range: range, string: string) } } 
  • Лучший способ проверить, работает ли iPhone приложение в первый раз
  • Доступ и использование MobileWiFi.framework
  • Как включить и использовать новые шрифты в iPhone SDK?
  • Как заставить UIMenuController работать для пользовательского представления?
  • Обнаружение режима полета на iOS
  • Ошибка кодового знака: идентификатор «iPhone Developer: x Xxxxx» не соответствует ни одному типу в любом профиле
  • Каков второй параметр NSLocalizedString ()?
  • Динамический (Default.png) splashscreen в 3.0
  • как изменить название проекта Xcode
  • Как продлить сертификат разработки iPhone?
  • Недопустимые права
  • Interesting Posts

    Как я могу разделить страницы PDF в середине?

    NETWORK_PROVIDER не предоставляет обновленные местоположения

    Как прочитать файл excel на C # без использования библиотек Microsoft.Office.Interop.Excel

    Как смонтировать раздел EFI в Windows 8.1, чтобы он был доступен для чтения и записи?

    Tail -f не отслеживать изменения файла

    React router изменяет URL, но не просматривает

    Как добавить шаблон проверки формы в Angular 2?

    Как переустановить загрузчик grub-efi на Fedora Linux?

    Как избежать больших if-утверждений и instanceof

    Можете ли вы хранить компакт-диски / DVD-диски в огнестойком сейфе?

    Как визуализировать глубину линейно в современном OpenGL с gl_FragCoord.z ​​в флеш-шейдере?

    Как быстро просмотреть тему?

    Как использовать Twitter Bootstrap 3 для сайта, не отвечающего требованиям?

    Кажется, что сервлет обрабатывает несколько одновременных запросов браузера синхронно

    Повернуть bitmap под реальным углом

    Давайте будем гением компьютера.