I'm trying to add a decimal after every 3 characters. (Counting backwards like this: 1,325,541 instead of 1325451.)
Here is what I tried:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSNumberFormatter *numberFormat = [[NSNumberFormatter alloc] init];
[numberFormat setGroupingSeparator:@","];
[numberFormat setGroupingSize:3];
[numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *amount = [numberFormat numberFromString:textField.text];
textField.text = [numberFormat stringFromNumber:amount];
return YES;
}
It doesn't insert a comma after every 3 characters. What can I do to fix it?
Well, this ends up being a little more nuanced than you might expect, but this is what I came up with:
As @bgfriend0's comment mentions, textField:shouldChangeCharactersInRange:replacementString
gets called before applying an edit to a text field (this is useful for other reasons). Meaning, that if your current string was 123
and a user goes to type in 4
, the method would be passed the following as parameters:
textField:
the textField, but note at this point textField.text
is 123
range:
NSRange{2, 0}string:
4And there is a way to make this function work from within that method, but there's a better way (I think).
After you instantiate your textField, add a target to listen for editing events:
[textField addTarget:self
action:@selector(formatNumberIfNeeded:)
forControlEvents:UIControlEventEditingChanged];
This will get called anytime an editing change happens in a UITextField
. The SEL
that we'll be performing will look like this:
- (void)formatNumberIfNeeded:(UITextField *)textField{
// you'll need to strip the commas for the formatter to work properly
NSString * currentTextWithoutCommas = [textField.text stringByReplacingOccurrencesOfString:@"," withString:@""];
NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber * numberFromString = [numberFormatter numberFromString:currentTextWithoutCommas];
NSString * formattedNumberString = [numberFormatter stringFromNumber:numberFromString];
textField.text = formattedNumberString;
}
Now, things get slightly more tricky if you need to localize, but cross that bridge if needed.
As for textField:shouldChangeCharactersInRange:replacementString
, that's a much better place to do character validation. So, a basic validation to check for letters could look like:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSRange illegalCharacterEntered = [string rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
if ( illegalCharacterEntered.location != NSNotFound ) {
return NO;
}
return YES;
}
So with those two bits of code, you'll be able to update the textfield string to include a comma every 3rd character, and users wont be able to enter any letters of the alphabet (but they can still input other 'illegal' characters, so extend that validation as needed).