iOS会在文本字段中自动添加连字符

我正在学习iOS开发,很难搞清楚控件的各种事件。 对于testing,我有一个UITextField,其中用户是要input一个string的格式:XXXX-XXXX-XXXX-XXXX

我希望能够检查每个条目之后字段中的文本的长度,并查看是否需要添加连字符。 我已经为此设置了我的IBAction函数,但是当我将其赋值给“Value Changed”事件时,它什么都不做,它在我编辑“Editing Did End”时工作正常,但只有当用户退出控制。

编辑:只需要添加,“编辑更改”事件导致它崩溃了。 我认为这是一个堆栈溢出或文本的设置再次调用事件处理程序的东西。

所以简而言之,每次用户在UITextField中input一个字符时,有没有办法设置一个事件处理程序呢?

要知道,以前的答案是可悲的不足。 天堂禁止您的用户input不正确的数字,并敢于尝试删除它! 公平地说,海报注意到代码可能不完美。 但是,它甚至不会编译,所以买家当心filter应该已经很高了。 如果你修正了编译错误并且尝试了代码,你会发现你可以很容易地结束与input不符合海报的格式。

以下是我用于将文本字段限制为格式为123-456-7890的电话号码的解决scheme。 调整其他数字格式是微不足道的。 请注意使用传递的NSRange 。 顺便说一下,即使使用数字虚拟键盘也需要拒绝非数字字符,因为用户仍然可以通过硬件键盘input非数字字符。

另一个说明。 在第4位和第7位input加上连字符使数字的删除变得容易一些。 如果您在第三和第六位数字后添加,则必须处理删除悬挂连字符的情况。 下面的代码避免了这种用例。

// Restrict entry to format 123-456-7890 - (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // All digits entered if (range.location == 12) { return NO; } // Reject appending non-digit characters if (range.length == 0 && ![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) { return NO; } // Auto-add hyphen before appending 4rd or 7th digit if (range.length == 0 && (range.location == 3 || range.location == 7)) { textField.text = [NSString stringWithFormat:@"%@-%@", textField.text, string]; return NO; } // Delete hyphen when deleting its trailing digit if (range.length == 1 && (range.location == 4 || range.location == 8)) { range.location--; range.length = 2; textField.text = [textField.text stringByReplacingCharactersInRange:range withString:@""]; return NO; } return YES; } 

对于这样的事情,我会build议使用UITextFieldDelegate来检测用户何时input一个新的字符。 设置您的文本字段的委托,如下所示:

 [textField setDelegate:self]; 

然后,根据需要实施委托方法:

 - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; // hide the keyboard return NO; } - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // every time the length reaches four, it gets reset to 0 and a '-' is added. static int currentLength = 0; if ((currentLength += [string length]) == 4) { currentLength = 0; [textField setText:[NSString stringWithFormat:@"%@%@%c", [textField text], string, '-']; return NO; } return YES; } 

这可能不完美,但我希望它有帮助!

dingo sky的答案是好的,但是在帮助未来的人发现这个解决scheme的绊脚石方面,存在一些问题。 Dingo的解决scheme允许您将长数字string粘贴到打破委托的“规则”的字段中,因为它只使用范围位置进行格式设置和长度。 (你可以有超过12个字符,而不是连字符)。

简单的解决scheme是计算结果string的长度,并且每次重新格式化。

Dingo的答案更新版本如下:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { //calculate new length NSInteger moddedLength = textField.text.length-(range.length-string.length); // max size. if (moddedLength >= 13) { return NO; } // Reject non-number characters if (range.length == 0 &&![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) { return NO; } // Auto-add hyphen before appending 4rd or 7th digit if ([self range:range ContainsLocation:3] || [self range:range ContainsLocation:7]) { textField.text = [self formatPhoneString:[textField.text stringByReplacingCharactersInRange:range withString:string]]; return NO; } return YES; } #pragma mark helpers -(NSString*) formatPhoneString:(NSString*) preFormatted { //delegate only allows numbers to be entered, so '-' is the only non-legal char. NSString* workingString = [preFormatted stringByReplacingOccurrencesOfString:@"-" withString:@""]; //insert first '-' if(workingString.length > 3) { workingString = [workingString stringByReplacingCharactersInRange:NSMakeRange(3, 0) withString:@"-"]; } //insert second '-' if(workingString.length > 7) { workingString = [workingString stringByReplacingCharactersInRange:NSMakeRange(7, 0) withString:@"-"]; } return workingString; } -(bool) range:(NSRange) range ContainsLocation:(NSInteger) location { if(range.location <= location && range.location+range.length >= location) { return true; } return false; } 

这是我的方法,甚至当你移动光标和/或删除文本的范围,甚至粘贴有效的文本时工作。基本上我的做法是每次重置文本,并在适当的地方添加连字符。 使它变得复杂的是,即使用户将光标移动到string的中间,它也将光标的位置重置到正确的位置。 不幸的是,有很多情况需要考虑。

我承认,对于这样一个简单的任务来说这是非常复杂的(绝对可以使用重大的清理工作)。 也有点低效,但是我们并没有在这里进行大量的计算。 据我所知,这是最安全的解决scheme。 我欢迎任何人certificate我的错误。

 -(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (range.location == 12 || (textField.text.length >= 12 && range.length == 0) || string.length + textField.text.length > 12 ) { return NO; } // Reject appending non-digit characters if (range.length == 0 && ![[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[string characterAtIndex:0]]) { return NO; } UITextRange* selRange = textField.selectedTextRange; UITextPosition *currentPosition = selRange.start; NSInteger pos = [textField offsetFromPosition:textField.beginningOfDocument toPosition:currentPosition]; if (range.length != 0) { //deleting if (range.location == 3 || range.location == 7) { //deleting a dash if (range.length == 1) { range.location--; pos-=2; } else { pos++; } } else { if (range.length > 1) { NSString* selectedRange = [textField.text substringWithRange:range]; NSString* hyphenless = [selectedRange stringByReplacingOccurrencesOfString:@"-" withString:@""]; NSInteger diff = selectedRange.length - hyphenless.length; pos += diff; } pos --; } } NSMutableString* changedString = [NSMutableString stringWithString:[[textField.text stringByReplacingCharactersInRange:range withString:string] stringByReplacingOccurrencesOfString:@"-" withString:@""]]; if (changedString.length > 3) { [changedString insertString:@"-" atIndex:3]; if (pos == 3) { pos++; } } if (changedString.length > 7) { [changedString insertString:@"-" atIndex:7]; if (pos == 7) { pos++; } } pos += string.length; textField.text = changedString; if (pos > changedString.length) { pos = changedString.length; } currentPosition = [textField positionFromPosition:textField.beginningOfDocument offset:pos]; [textField setSelectedTextRange:[textField textRangeFromPosition:currentPosition toPosition:currentPosition]]; return NO; } 

或者:只要使用这个https://github.com/romaonthego/REFormattedNumberField

经过一番研究,我想下面的解决scheme可以自动地以相同的时间间隔添加/删除一个新的string。

说明: 1.插入一个新的字符

  Text : XXXX-XXXX- Location : 0123456789 Objective : We've to insert new character's at locations 4,9,14,19,etc. Since equal spacing should be 4. Let's assume y = The location where the new charcter should be inserted, z = Any positive value ie,[4 in our scenario] and x = 1,2,3,...,n Then, => zx + x - 1 = y eg, [ 4 * 1 + (1-1) = 4 ; 4 * 2 + (2 - 1) = 9 ; etc. ] => x(z + 1) - 1 = y => x(z + 1) = (1 + y) => ***x = (1 + y) % (z + 1)*** eg, [ x = (1 + 4) % (4 + 1) => 0; x = (1 + 9) % (4 + 1) => 0 ] The reason behind finding 'x' leads to dynamic calculation, because we can find y, If we've 'z' but the ultimate objective is to find the sequence 'x'. Of course with this equation we may manipulate it in different ways to achieve many solutions but it is one of them. 2. Removing two characters (-X) at single instance while 'delete' keystroke Text : XXXX-XXXX- Location : 0123456789 Objective : We've to remove double string when deleting keystroke pressed at location 5,10,15,etc. ie, The character prefixed with customized space indicator Note: 'y' can't be zero => zx + x = y eg, [ 4 * 1 + 1 = 5 ; 4 * 2 + 2 = 10; 4 * 3 + 3 = 15; etc.] => x(z + 1) = y => ***x = y % (z + 1)*** eg, [ x = (5 % (4 + 1)) = 0; x = (10 % (4 + 1)) = 0; etc. ] 

Swift解决scheme:

 let z = 4, intervalString = " " func canInsert(atLocation y:Int) -> Bool { return ((1 + y)%(z + 1) == 0) ? true : false } func canRemove(atLocation y:Int) -> Bool { return (y != 0) ? (y%(z + 1) == 0) : false } func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let nsText = textField.text! as NSString if range.length == 0 && canInsert(atLocation: range.location) { textField.text! = textField.text! + intervalString + string return false } if range.length == 1 && canRemove(atLocation: range.location) { textField.text! = nsText.stringByReplacingCharactersInRange(NSMakeRange(range.location-1, 2), withString: "") return false } return true } 

你可以试试这个:

 [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; 

它应该真的与这个,你还应该张贴一些代码。 在注册事件之后,您应该检查string的长度并添加连字符。

目前接受的答案没有考虑复制/粘贴到文本字段

而不是使用委托的“shouldChangeCharactersInRange”,从文本字段连接一个IBAction文本更改操作。 然后添加下面的代码:

 - (IBAction)textFieldDidChange:(UITextField *)sender { if (sender.text.length > 0) { NSString *text = sender.text; text = [text stringByReplacingOccurrencesOfString:@"-" withString:@""]; text = [text substringToIndex:MIN(20, text.length)]; NSMutableArray *parts = [NSMutableArray array]; int counter = 0; while (text.length > 0) { [parts addObject:[text substringToIndex:MIN(5, text.length)]]; if (text.length > 5) { text = [text substringFromIndex:5]; } else { text = @""; } counter ++; } text = [parts objectAtIndex:0]; [parts removeObjectAtIndex:0]; for (NSString *part in parts) { text = [text stringByAppendingString:@"-"]; text = [text stringByAppendingString:part]; } sender.text = text; } } 

这是这样做的正确方法,因为如果用户将文本粘贴到文本字段中,则需要相应地格式化所有粘贴的文本(而不是一次一个字符)。

看看“NBAsYouTypeFormatter”和“NBPhoneNumberUtil”。 这些课程将会帮助你很多。