IOS automatically adds hyphens to textboxes

I am learning iOS development and it is difficult for me to define various events for controls. For the test, I have a UITextField where the user must enter a string in the format: XXXX-XXXX-XXXX-XXXX

I want to be able to check how long the text in the field is after each entry, and see if it needs to be added with a hyphen. I configured the IBAction function for this, but when I assigned it to the "Value Changed" event, it does nothing, it works fine when I set it to "Editing Did End", but it will only be called when the user goes out of control .

Edit: just to add, the Edit Edited event also crashes. I assume this is a stack overflow or something where setting the text again triggers an event handler.

In short, is there a way to set an event handler for each user input to a character in a UITextField?

+6
ios objective-c hyphen
06 Aug 2018-11-18T00:
source share
8 answers

Remember that the previous answer is terribly inadequate. Heaven forbids your user to enter the wrong number and dare to try to delete it! In fairness, the poster noted that the code may not work this way. But then it wonโ€™t even compile, so the buyerโ€™s filter should already be high. If you fix the compilation error and try the code, you will see that you can easily get a result that does not match the specified poster format.

Here is the solution that I used to limit the text field to a phone number in the format 123-456-7890. Setting up other digital formats is trivial. Note the use of the passed NSRange . And BTW, rejecting non-digital characters is necessary even when using the digital virtual keyboard, because users can still enter numbers without using a hardware keyboard.

One more note. I add a hyphen after entering the 4th and 7th digits to simplify the removal of digits. If you add after the 3rd and 6th digits, you will have to handle the case of removing the hyphen. The code below avoids this use case.

// 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; } 
+33
Jul 10 2018-12-12T00:
source share

For something like this, I suggest using UITextFieldDelegate to detect whenever a user enters a new character. Set the text field delegate as follows:

 [textField setDelegate:self]; 

Then follow the appropriate delegate methods:

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

This may not work perfectly, but I hope this helps!

+6
Aug 6 '11 at 18:11
source share

dingo sky answers well, but there are a couple of problems in striving to help future people who stumble upon this solution. Dingo's solution allows you to insert long numeric strings into a field that violates the delegate's "rules" because it uses only the range location for formatting and length. (you can have more than 12 characters and not have a hyphen).

A simple solution is to calculate the length of the resulting string and reformat it every time.

Updated version of Dingo answer below:

 - (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; } 
+6
Dec 20 '13 at 17:07
source share

Here my approach works even when you move the cursor and / or delete ranges of text or even insert valid text. Basically my approach is to reset the text every time and if necessary, add hyphens. The difficulty is that it also resets the cursor to the right place, even if the user moves the cursor to the middle of the line. Unfortunately, there are many cases to consider.

I admit that this is ridiculously difficult for such a simple task (definitely a major cleanup could be used). Also a bit inefficient, but we are not doing intensive calculations here. As far as I can tell, this is the most reliable solution here; I welcome everyone to prove that I am wrong.

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

OR: just use https://github.com/romaonthego/REFormattedNumberField

+2
May 10 '14 at 23:52
source share

After a bit of research, I assume that the solution below can automatically add / remove a new line at equal intervals.

Explanation: 1. Insert a new character.

  Text : XXXX-XXXX- Location : 0123456789 Objective : We've to insert new character at locations 4,9,14,19,etc. Since equal spacing should be 4. Let 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. ] 

Solution in Swift:

 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 } 
+2
Jul 25 '16 at 6:09
source share

You can try the following:

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

This should work with this, you should also post the code. After registering with the event, you should simply check the line length and add a hyphen.

+1
Aug 6 '11 at 17:32
source share

The current accepted answer does not account for copying / pasting into the text box

Instead of using the delegate "shouldChangeCharactersInRange", connect the IBAction to the text box with the Text Did Change action. Then add the following code:

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

This is the right way to do this because if the user inserts text into a text field, you want to format all the inserted text (not just one character at a time).

0
Jul 18 '14 at 0:31
source share

Take a look at "NBAsYouTypeFormatter" and "NBPhoneNumberUtil". These classes will help you a lot.

0
Apr 07 '15 at 22:57
source share



All Articles