Мне было интересно, как я могу форматировать textField, который я использую для номера телефона (например, как "Добавить новый контакт" на iPhone. Когда я вхожу в новый мобильный телефон, например, 1236890987, он форматирует его как (123 ) 689-0987.) У меня уже есть клавиатура в качестве цифровой клавиатуры.
UITextField для номера телефона
Ответ 1
Вот мое решение.. отлично работает! Форматирует номер телефона в реальном времени. Примечание. Это для 10-значных телефонных номеров. И в настоящее время он автоматически форматирует его, как (xxx) xxx-xxxx.. tweak для вашего сердца.
Сначала в shouldChangeCharactersInRange
вы хотите собрать всю строку для текстового поля телефона и передать ее функции проверки/форматирования.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* totalString = [NSString stringWithFormat:@"%@%@",textField.text,string];
// if it 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 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;
}
Ответ 2
Вот как вы можете сделать это в 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
}
}
Ответ 3
Обновленный ответ от 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
}
}
Ответ 4
Я боролся с этим в течение нескольких часов, вот что у меня:
- (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;
}
Я надеюсь, что кто-то может внести свой вклад.
Ответ 5
Ниже функция принудительно форматирует (999) 333-5555 на текстовом поле:
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
}
}
Ответ 6
Вот мой пример. Что близко к тому, что Apple делает в приложении "Телефон и контакты" (по крайней мере, когда ваш регион настроен на U.S., я не уверен, изменилось ли поведение в каждом регионе).
Меня особенно интересовали форматирование до 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;
}
Ответ 7
Это решение отлично подходит для североамериканских номеров без префикса международного набора (+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;
}
Ответ 8
Обновлен ответ для 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
}
Работала для меня отлично, надеюсь, что это сработает для вас тоже.
Ответ 9
Вы можете вызвать этот метод всякий раз, когда вам нужно обновить 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: "#")
Ответ 10
Вы можете добавить номер телефона, например 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;
}
}
Ответ 11
Swift 4 (и без NSString)
для формата +X (XXX) XXX-XXXX или +X (XXX) XXX-XX-XX Обновлено и немного
class ViewController: UIViewController, UITextFieldDelegate {
var myPhoneNumber = String()
@IBOutlet weak var phoneTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
phoneTextField.delegate = self
phoneTextField.keyboardType = .phonePad
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.phoneTextField) && textField.text == ""{
textField.text = "+7(" //your country code default
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == phoneTextField {
let res = phoneMask(phoneTextField: phoneTextField, textField: textField, range, string)
myPhoneNumber = res.phoneNumber != "" ? "+\(res.phoneNumber)" : ""
print("Phone - \(myPhoneNumber) MaskPhone=\(res.maskPhoneNumber)")
if (res.phoneNumber.count == 11) || (res.phoneNumber.count == 0) {
//phone number entered or completely cleared
print("EDIT END: Phone = \(myPhoneNumber) MaskPhone = \(res.maskPhoneNumber)")
}
return res.result
}
return true
}
}
extension UITextFieldDelegate {
func phoneMask(phoneTextField: UITextField, textField: UITextField, _ range: NSRange, _ string: String) -> (result: Bool, phoneNumber: String, maskPhoneNumber: String) {
let oldString = textField.text!
let newString = oldString.replacingCharacters(in: Range(range, in: oldString)!, with: string)
//in numString only Numeric characters
let components = newString.components(separatedBy: CharacterSet.decimalDigits.inverted)
let numString = components.joined(separator: "")
let length = numString.count
let maxCharInPhone = 11
if newString.count < oldString.count { //backspace to work
if newString.count <= 2 { //if now "+7(" and push backspace
phoneTextField.text = ""
return (false, "", "")
} else {
return (true, numString, newString) //will not in the process backspace
}
}
if length > maxCharInPhone { // input is complete, do not add characters
return (false, numString, newString)
}
var indexStart, indexEnd: String.Index
var maskString = "", template = ""
var endOffset = 0
if newString == "+" { // allow add "+" if first Char
maskString += "+"
}
//format +X(XXX)XXX-XXXX
if length > 0 {
maskString += "+"
indexStart = numString.index(numString.startIndex, offsetBy: 0)
indexEnd = numString.index(numString.startIndex, offsetBy: 1)
maskString += String(numString[indexStart..<indexEnd]) + "("
}
if length > 1 {
endOffset = 4
template = ")"
if length < 4 {
endOffset = length
template = ""
}
indexStart = numString.index(numString.startIndex, offsetBy: 1)
indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
maskString += String(numString[indexStart..<indexEnd]) + template
}
if length > 4 {
endOffset = 7
template = "-"
if length < 7 {
endOffset = length
template = ""
}
indexStart = numString.index(numString.startIndex, offsetBy: 4)
indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
maskString += String(numString[indexStart..<indexEnd]) + template
}
var nIndex: Int; nIndex = 7
// //format +X(XXX)XXX-XX-XX -> if need uncoment
// nIndex = 9
//
// if length > 7 {
// endOffset = 9
// template = "-"
// if length < 9 {
// endOffset = length
// template = ""
// }
// indexStart = numString.index(numString.startIndex, offsetBy: 7)
// indexEnd = numString.index(numString.startIndex, offsetBy: endOffset)
// maskString += String(numString[indexStart..<indexEnd]) + template
// }
if length > nIndex {
indexStart = numString.index(numString.startIndex, offsetBy: nIndex)
indexEnd = numString.index(numString.startIndex, offsetBy: length)
maskString += String(numString[indexStart..<indexEnd])
}
phoneTextField.text = maskString
if length == maxCharInPhone {
//dimiss kayboard
phoneTextField.endEditing(true)
return (false, numString, newString)
}
return (false, numString, newString)
}
}
Ответ 12
Вот мой код Swift 2, слегка локализованный с точки зрения Великобритании.
Он будет отформатировать:
+11234567890 как +1 (123) 456 7890
+33123456789 как +33 1 23 45 67 89
+441234123456 как +44 1234 123456 (это было затем локализовано как 01234 123456), потому что мне не нужно видеть код страны для номеров в Великобритании.
Вызвать следующее:
initInternationalPhoneFormats() //this just needs to be done once
var formattedNo = formatInternationalPhoneNo("+11234567890")
Если у вас есть другие коды страны и форматы или улучшения кода, пожалуйста, дайте мне знать.
Enjoy.
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)
}
Ответ 13
Мое решение для формата + 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
}
Ответ 14
К сожалению, вы должны сделать это сами. В контактном приложении используются недокументированные API. По какой-то причине добавление форматов ввода в текстовые поля не отображается на iPhone так, как на Mac. Не стесняйтесь записывать отчет об ошибке улучшения функции.
Ответ 15
Надеюсь, что я собираюсь сказать, будет полезно для новых людей, программирующих на iOS, как и я. Я сделал то, что предлагает zingle-dingle (спасибо много!). Чтобы помочь новым, код и то, что я перечислил, могут вам помочь. 1. Вы должны добавить UITextFieldDelegate в файл заголовка. 2. UITextField должен связать делегата с представлением, в моем случае UIViewController, который является файлом заголовка. 3. UITextField должен быть установлен, это означает, yourtextfile.delegate = self, в файле ".m".
Ответ 16
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
}
Ответ 17
Вот мое решение для формата телефона 05xx xxx xxxx. В начале я установил
phoneTextField.delegate = self
phoneTextField.text = "05" // I don't let user to change it.
Он также охватывает случаи копирования/вставки для положения курсора.
Возможно, это помогает кому-то для разных форматов.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if range.location == 0 || range.location == 1 {
return false
}
var phone = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if phone.length > 13 {
return false
}
phone = phone.replacingOccurrences(of: " ", with: "")
if phone.characters.count > 7 {
phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 4))
phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 8))
} else if phone.characters.count > 4 {
phone.insert(" ", at: phone.index(phone.startIndex, offsetBy: 4))
}
let text = textField.text
let stringToStart = text?.substring(to: (text?.index((text?.startIndex)!, offsetBy: range.location))!)
let stringToStartCount = ((stringToStart?.components(separatedBy: " ").count)! > 1) ? (stringToStart?.components(separatedBy: " ").count)!-1 : 0
var cursorIndex = range.location + string.length - stringToStartCount
if cursorIndex > 7 {
cursorIndex += 2
} else if cursorIndex > 4 {
cursorIndex += 1
}
textField.text = phone
textField.selectedTextRange = textField.textRange(from: textField.position(from: textField.beginningOfDocument, offset: cursorIndex)!, to: textField.position(from: textField.beginningOfDocument, offset: cursorIndex)!)
return false
}
Ответ 18
Обновлен ответ от "iOS Unit" для Swift 3 с форматом + X (XXX) XXX-XXXX:
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.phoneTextField) {
textField.text = "+"
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField == self.phoneTextField) {
let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if (newString.characters.count < (textField.text?.characters.count)! && newString.characters.count >= 1) {
return true // return true for backspace to work
} else if (newString.characters.count < 1) {
return false; // deleting "+" makes no sence
}
if (newString.characters.count > 17 ) {
return false;
}
let components = newString.components(separatedBy: CharacterSet.decimalDigits.inverted)
let decimalString = components.joined(separator: "") as NSString
let length = decimalString.length
var index = 0
let formattedString = NSMutableString()
formattedString.append("+")
if (length >= 1) {
let countryCode = decimalString.substring(with: NSMakeRange(0, 1))
formattedString.append(countryCode)
index += 1
}
if (length > 1) {
var rangeLength = 3
if (length < 4) {
rangeLength = length - 1
}
let operatorCode = decimalString.substring(with: NSMakeRange(1, rangeLength))
formattedString.appendFormat(" (%@) ", operatorCode)
index += operatorCode.characters.count
}
if (length > 4) {
var rangeLength = 3
if (length < 7) {
rangeLength = length - 4
}
let prefix = decimalString.substring(with: NSMakeRange(4, rangeLength))
formattedString.appendFormat("%@-", prefix)
index += prefix.characters.count
}
if (index < length) {
let remainder = decimalString.substring(from: index)
formattedString.append(remainder)
}
textField.text = formattedString as String
if (newString.characters.count == 17) {
textField.resignFirstResponder()
}
return false
}
return true
}
Ответ 19
Вы можете использовать эту библиотеку https://github.com/luximetr/AnyFormatKit
Пример
let textInputController = TextInputController()
let textInput = TextInputField() // or TextInputView or any TextInput
textInputController.textInput = textInput // setting textInput
let formatter = TextInputFormatter(textPattern: "### (###) ###-##-##", prefix: "+12")
textInputController.formatter = formatter // setting formatter
Просто установите ваш textField в textInputController и отформатируйте текст с шаблоном, который вы установили.
Или
let phoneFormatter = TextFormatter(textPattern: "### (###) ###-##-##")
phoneFormatter.formattedText(from: "+123456789012") // +12 (345) 678-90-12
для полной строки формата
Ответ 20
u нужно сделать это вручную. получать уведомление о текстовом поле и проверять длину текста поля и форматировать его в соответствии со страной. если какая-либо проблема сообщит мне. Я сделал это
Ответ 21
У меня есть решение для этого, но у него есть некоторый недостаток, посмотрите, можете ли вы его изменить и использовать. Используя это, вы можете добиться того, что номер телефона ограничится 10 цифрами и отформатируйте его в соответствии с форматом США.
#define MAX_LENGTH 10
Реализовать его в методе делегата UITextField
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSInteger insertDelta = string.length - range.length;
if (PhoneNumber_txt.text.length + insertDelta > MAX_LENGTH)
{
return NO; // the new string would be longer than MAX_LENGTH
}
else {
range.length = 3;
range.location = 3;
PhoneNumber_txt.text = [NSString stringWithFormat:@"(%@)%@-%@", [PhoneNumber_txt.text substringToIndex:3], [PhoneNumber_txt.text substringWithRange:range], [PhoneNumber_txt.text substringFromIndex:6]];
return YES;
}
}
Ответ 22
- (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;
}
Ответ 23
объектное решение c для формата +X (XXX) XXX-XXXX
- (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;
}
Ответ 24
Это мое решение с помощью Swift 4 для форматирования нескольких типов (123) 689-0987
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let currentText:String = textField.text else {return true}
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
}
Ответ 25
Я использую этот формат X (XXX) XXX XX XX, это работа в Турции,
Я использую его с TableView с 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
}
}
и вы можете вызвать эту функцию в
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String, indexPath: IndexPath) -> Bool {
}
в любом indexPath, что ваше текстовое поле в нем
например, мое текстовое поле в indexPath номер 1, поэтому код будет
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)
}
}