NSNumberFormatter change decimal separator style - objective-c

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
if (string.length == 0) {
return YES;
}
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* candidateNumber;
NSString* candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
range = NSMakeRange(0, [candidateString length]);
[numberFormatter getObjectValue:&candidateNumber forString:candidateString range:&range error:nil];
if (([candidateString length] > 0) && (candidateNumber == nil || range.length < [candidateString length])) {
return NO;
}
else
{
return YES;
}
Hi, with this code i can insert only decimal values in a textfield.
The decimal separator is a comma ","
How do I change it to a dot "." ?
Thanks

There is a little thing called Localization. Every language uses a different character as a decimal separator. Where English uses a decimal point, other languages use a comma (or other characters).
When you create a NSNumberFormatter it uses the system locale (NSLocale instance) to decide about the decimal separator (and grouping separator and other things).
If you want a fixed behavior, then just set a different locale using [NSNumberFormatter setLocale:]
Also note there is one special kind of locale
[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] which defines a special locale which cannot be changed by user settings and is always the same.
In this case, using a NSNumberFormatter is not the best idea. This is one of the cases when you want to use a regular expression.

Related

how to put currency symbol while and after typing in UITextfield?

I have this stock market calculator that I am working on and I searched Apple documentation, the internet, here at StackOverFlow, but wasn't successful in finding the answer..
I have a UITextfield in which the user will input a currency value. What I want to implement is when the user is typing or at least after he finishes type the value the textfield would also display the currency symbol corresponding to the locale he is.
It's like a placeholder, but not the one we have in xcode, cause xcode's is there before we type and the one I want should be there while typing and after it. I could use a background image with the currency in it, but then I wouldn't be able to localize the app.
So if any one could help, I would appreciate.
Thanks in advance.
You have to use NSNumberFormatter to achieve this.
Try the following code, and by this, once you entered the values and when you end editing, the values will be formatted with current currency.
-(void)textFieldDidEndEditing:(UITextField *)textField {
NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setLocale:[NSLocale currentLocale]];
[currencyFormatter setMaximumFractionDigits:2];
[currencyFormatter setMinimumFractionDigits:2];
[currencyFormatter setAlwaysShowsDecimalSeparator:YES];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *someAmount = [NSNumber numberWithDouble:[textField.text doubleValue]];
NSString *string = [currencyFormatter stringFromNumber:someAmount];
textField.text = string;
}
The easiest way would be to put a label with right aligned text up against your text field, which would have left aligned text.
When the user starts to edit the textfield, set the currency symbol:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.currencyLabel.text = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];
}
If you want to keep it as part of the text in the textField, it becomes a little more complicated as you need to keep them from deleting the symbol once you put it there:
// Set the currency symbol if the text field is blank when we start to edit.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if (textField.text.length == 0)
{
textField.text = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
// Make sure that the currency symbol is always at the beginning of the string:
if (![newText hasPrefix:[[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol]])
{
return NO;
}
// Default:
return YES;
}
As #Aadhira points out, you should also be formatting the currency by using a number formatter since you are displaying it to the user.

UIKeyboardTypeDecimalPad Limit Decimal Point and handling localization [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Decimal point in UIKeyboardTypeDecimalPad can’t be used in mathematical calculation
I have an iPhone app where we are using the UIKeyboardTypeDecimalPad for input which has been working fine for us until we have started to localize the application, the problem we now face is that when the language is switched to French or German the decimal point on the keypad changes from a full stop (.) to a comma (,).
We are currently running this code to restrict the input of multiple decimal points i.e. 12.4.4 with this code it will only allow 12.4 to be entered
This works fine but now we also need to check for the comma and also convert the users input for our calculations if it has a comma
Is there a better way to restrict the input on the keypad for both comma and full stop?
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *currentText = textField.text;
if ([currentText rangeOfString:#"." options:NSBackwardsSearch].length == 0) {
return YES;
} else {
if ([string rangeOfString:#"." options:NSBackwardsSearch].length == 0) {
return YES;
} else {
return NO;
}
}
return NO;
}
Thanks Aaron
I have managed to work this out this will validate that the number is in decimal format and accept , or .
Aaron
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* candidateNumber;
NSString* candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
range = NSMakeRange(0, [candidateString length]);
[numberFormatter getObjectValue:&candidateNumber forString:candidateString range:&range error:nil];
if (([candidateString length] > 0) && (candidateNumber == nil || range.length < [candidateString length])) {
[numberFormatter release];
return NO;
}
else {
[numberFormatter release];
return YES;
}
}

NSNumberFormatter only allowing 4 digits

Please can you tell me why my NSNumberFormatter is only letting me use 4 digits (i.e £2,222) instead of infinite digits?
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *input = [textField.text stringByAppendingString:string];
[textField setText:[self numberFormattedString:input]];
return NO;
}
- (NSString *) numberFormattedString:(NSString *)str {
str = [str stringByReplacingOccurrencesOfString:#"£" withString:#""];
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-UK"];
[formatter setLocale:locale];
[locale release];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
return [formatter stringFromNumber:[NSNumber numberWithFloat:[str floatValue]]];
}
Edit--
When I type a fifth digit, having already 4 digits inside the UITextField, the textField's text is reset back to fifth digit typed alone.
E.G
I enter 1000 into the UITextField, I then enter a further digit of 5. As 5 is the fifth digit, the UITextField's text gets reset to the fifth digit alone. The UITextField now displays '5'.
TIA.
XcodeDev
The problem is that a comma is breaking [NSString floatValue]. When you get to entering the fifth digit, str ends up looking something like 1,0005, which floatValue converts to a value of 1 since it doesn't know how to deal with the comma and/or the fact that there are too many digits after it. Add this code
str = [str stringByReplacingOccurrencesOfString:#"," withString:#""];
as the first or second line of numberFormattedString and it will work.
What's probably happening is that as the user types, the formatter is inserting commas at the thousand marks. You aren't stripping those out when you do the reformatting like you are with the pound sign, so at some point the formatting function is being given a string like "1,000".
When you try to get the floatValue of that to convert it back into an NSNumber for reformatting, floatValue returns 1 because it can't parse commas.
Solution: add this extra line to your formatting function:
str = [str stringByReplacingOccurrencesOfString:#"," withString:#""];

NSNumberFormatter not allowing decimal input

If I enter a decimal point '.' into my UITextField, the number formatter called does not recognise the decimal point and continues as if the decimal point has not been entered. I.e If I entered 200.9, the decimal point would not show up in the textfield and the text of the textfield would be 2009.
I want to limit the number of digits after the decimal point to 2 as I believe I am doing below. Please can you tell me what I am doing to cause this?
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
BOOL isDeleting = [textField.text substringWithRange:range].length > string.length;
int index = [textFields indexOfObject:textField];
NSString *input;
if (isDeleting == NO)
input = [textField.text stringByAppendingString:string];
else {
NSMutableString *str = [textField.text mutableCopy];
[str deleteCharactersInRange:range];
input = [[str copy] autorelease];
[str release];
}
if ([input isEqualToString:#"£"] || ([input isEqualToString:#""] && index != 1)) {
[textField setText:#"£"];
}
else {
if (index != 1)
[textField setText:[self numberFormattedString:input]];
else
[textField setText:input];
}
return NO;
}
- (NSString *) numberFormattedString:(NSString *)str {
str = [str stringByReplacingOccurrencesOfString:#"£" withString:#""];
str = [str stringByReplacingOccurrencesOfString:#"," withString:#""];
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-UK"];
[formatter setLocale:locale];
[locale release];
[formatter setAllowsFloats:YES];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
[formatter setDecimalSeparator:#"."];
return [formatter stringFromNumber:[NSNumber numberWithFloat:[str floatValue]]];
}
TIA.
Let's say you enter the number 100 and then a decimal point. When numberFormattedString is called with the string £100., it's going to get rid of the £, and str will contain the string 100. which [str floatValue] converts to the float value 100, and finally your number formatter spits it back out as the string £100 without any decimal point. So basically [str floatValue] is killing your decimal point.
One solution is to check for when you get the decimal point as your replacement string in the text field delegate method, and skip calling numberFormattedString in that case. Then when the user enters the next digit, you can carry on calling numberFormattedString, and the conversion should happen correctly. You'll just have to make sure that the user can only enter one decimal point.
EDIT: I just realized that my suggested solution still won't work if you enter a 0 after the decimal point (e.g. 100.0), but I'm sure there is a minor tweak that you can figure out to solve that.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *numSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789."];
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
int charCount = [newString length];
if ([newString rangeOfCharacterFromSet:[numSet invertedSet]].location != NSNotFound
|| [string rangeOfString:#"."].location != NSNotFound
|| charCount > 15) {
return NO;
}
// if (charCount == 4 || charCount == 9 || charCount==13) {
// newString = [newString stringByAppendingString:#"."];
// }
NSLog(#"IN method");
textField.text = newString;
return NO;
}

UITextField - UIKeyboardTypeDecimalPad on iPad?

On the iPad...
textField.keyboardType = UIKeyboardTypeDecimalPad;
...just shows the regular keyboard, but starting on the numbers at the top (with lots of punctuation underneath).
But it's to type in a number. I only want the users to be able to type numbers and a decimal point, like UIKeyboardTypeDecimalPad does on the iPhone.
Is there any way to make the irrelevant keys go away and leave my user alone?
Setting a UITextField's keyboardType only makes it easier for a user to enter appropriate characters. Even on the iPhone, users can enter other characters via a hardware keyboard, or by pasting in a string.
Instead, implement UITextFieldDelegate's -textField:shouldChangeCharactersInRange:replacementString: to validate user input. You also probably don't really want to hardcode the digits 0-9 and a period. Users in some locales, for example, separate whole numbers from decimals with a comma:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *candidate = [[textField text] stringByReplacingCharactersInRange:range withString:string];
if (!candidate || [candidate length] < 1 || [candidate isEqualToString:#""])
{
return YES;
}
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:candidate];
if (!number || [number isEqualToNumber:[NSDecimalNumber notANumber]])
{
return NO;
}
return YES;
}
Alternately, you might perform validation when the user finishes entering text, in –textFieldShouldReturn:, – textFieldShouldEndEditing:, or – textFieldDidEndEditing: as desired.
This is not necessarily a foolproof solution, but it matched my needs and might be helpful to others. The concern would be that the number chars are hardcoded. I'm not sure of locales that use other numbers chars, but they can be added as needed.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *candidate = [[textField text] stringByReplacingCharactersInRange:range withString:string];
// Ensure that the local decimal seperator is used max 1 time
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
NSString *decimalSymbol = [formatter decimalSeparator];
if ([candidate componentsSeparatedByString:decimalSymbol].count > 2) return NO;
// Ensure that all the characters used are number characters or decimal seperator
NSString *validChars = [NSString stringWithFormat:#"0123456789%#", decimalSymbol];
if ([candidate stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:validChars]].length) return NO;
return YES;
}
I know this question has been inactive for quite a while, but this might help somebody out there.
You can try implementing this one https://github.com/azu/NumericKeypad. The coder implemented his own number pad buy subclassing the UITextField
Link this up to your textField's editingChanged method. You can edit the characters around as you feel the need to.
- (IBAction)numberValidator:(id)sender {
NSMutableString *txt1 = [[NSMutableString alloc] initWithString:_numbersOnlyField.text];
for (unsigned int i = 0; i < [txt1 length]; i++) {
NSString *character = [[NSString alloc] initWithFormat:#"%C", [txt1 characterAtIndex:i]];
// Erase any characters you don't like, but you don't feel the user needs to be alerted about
else if ([character isEqualToString:#" "]){
[txt1 deleteCharactersInRange:NSMakeRange(i, 1)];
_numbersOnlyField.text = [[NSString alloc] initWithString:txt1];
}
// Alert the user that they shouldn't enter anything besides numbers
if ([character integerValue] == 0 && ![character isEqualToString:#"0"]) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle: #"Numbers only please!"
message: #"Please only enter numbers in the \"<your text field's name here>\" text field"
delegate: nil
cancelButtonTitle:#"Sorry..."
otherButtonTitles:nil];
[alert show];
[txt1 deleteCharactersInRange:NSMakeRange(i, 1)];
_numbersOnlyField.text = [[NSString alloc] initWithString:txt1];
}
}
}
You can also do it programmatically through the UIControlEventValueChanged method.
This is just a solution I came up with myself and I definitely don't consider myself a professional, so there might be some flaws I'm overlooking, but this works pretty well for me.