Reputation: 920
I have created a text field to enter an amount of money. I want the user to be able to enter only one decimal point. I implemented that in the -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
method.
In the general case it works fine, but if backspace is pressed and the single decimal point is deleted, after that it still assumes that a decimal point has been entered, and so does not accept the decimal point again.
I need to reset the decimalPointEntered
flag whenever the decimal point is deleted by pressing backspace. How to do that ?
Upvotes: 7
Views: 10602
Reputation: 847
I would always prefer a regex over some piece of code based rule for such kinds of scenario.
To restrict one decimal point and one character after it, use below;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Only allow one decimal point and 1 digit after it
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSString *expression = @"^[0-9]$*((\\.|,)[0-9]{0,1})?$";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString options:0 range:NSMakeRange(0, [newString length])];
return numberOfMatches != 0;
return YES;
}
The above code will make sure that the text field only contains one decimal point and only one character after it.
You can play with this regex and create rule based on your requirement.
Upvotes: 1
Reputation: 2448
I have a very similar solution. Worked better for me. It also validates text input.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSLog(@"in shouldChangeCharactersInRange");
if([string length]==0){
return YES;
}
//Validate Character Entry
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789,."];
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if ([myCharSet characterIsMember:c]) {
//now check if string already has 1 decimal mark
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *sep = [newString componentsSeparatedByString:@"."];
NSLog(@"sep: %@ count: %d" ,sep,[sep count]);
if([sep count]>2) return NO;
return YES;
}
}
return NO;
}
Upvotes: 3
Reputation: 1750
Try this it is a swift code but you can refer the logic:-
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if(string == "." ){
let countdots = textField.text!.componentsSeparatedByString(".").count - 1
if countdots > 0 && string == "."
{
return false
}
}
return true
}
Upvotes: 1
Reputation: 35783
I am limiting my user to input amount should be like this
40543.48
So I updated shouldChangeCharactersInRange method this way
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; {
if (textField == self.txtFieldTransferAmount)
{
NSString *updatedText = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *stringsArray = [updatedText componentsSeparatedByString:@"."];
// Before decimal only 5 digit allowed
if (stringsArray.count > 0)
{
NSString *dollarAmount = stringsArray[0];
if (dollarAmount.length > 5)
return NO;
}
// After decimal only 2 digit allowed
if (stringsArray.count > 1)
{
NSString *centAmount = stringsArray[1];
if (centAmount.length > 2)
return NO;
}
// Only one . decimal allowed
if (stringsArray.count > 2)
return NO;
if (textField.text.length < 8) {
//User should able to enter only 0-9 and . characters
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
return [string isEqualToString:filtered];
}
else
{
if (range.length > 0)
{
return true;
}
else{
return false;
}
}
}
return true;
}
Upvotes: 4
Reputation: 2080
I use this method to limit the number of decimal characters to one AND allow the user to enter negative amounts if they need to (i.e. for discounts):
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"1234567890.-"] invertedSet];
if ([string rangeOfCharacterFromSet:cs].location == NSNotFound) {
NSString *newString = [[textField text] stringByReplacingCharactersInRange:range withString:string];
// check number of decimal chars used (maximum of one)
NSArray *array = [newString componentsSeparatedByString:@"."];
if ([array count] <= 2) {
// check negative chars (maximum of one AND it must be at the front)
array = [newString componentsSeparatedByString:@"-"];
if (1 == [array count]) {
return YES; // no negatives
} else if (2 == [array count]) {
return ('-' == [newString characterAtIndex:0]); // return YES if first char is negative only
} else {
return NO; // too many negative chars
}
} else {
return NO; // too many decimal chars
}
} else {
return NO; // invalid character
}
Upvotes: 0
Reputation: 797
This is the easiest way is to do this.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *explodedNumbersArray = [newString componentsSeparatedByString:@"."];
// We check if the array has 3 or more items which means that it has 2 decimal places or more
// we return NO if that happens so that the textfield will not recognize input
if([explodedNumbersArray count] >= 3) {
return NO;
}
return YES;
}
Note: Make sure that a view or view controller that should receive the delegate notifications should conform to the UITextFieldDelegate.
Upvotes: 0
Reputation: 845
May this help someone ..
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
// if . at the beggining
if ([newString isEqualToString:@"."] && newString.length== 1) {
textField.text = @"0.";
return NO;
}
// do not allow . more then once
NSArray *components = [newString componentsSeparatedByString:@"."];
if([components count] > 2)
{
return NO;
}
Upvotes: 2
Reputation: 147
This works fine for me. Try this code:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *sep = [newString componentsSeparatedByString:@"."];
if([sep count] >= 2)
{
NSString *sepStr=[NSString stringWithFormat:@"%@",[sep objectAtIndex:1]];
return !([sepStr length]>1);
}
return YES;
}
Upvotes: 10
Reputation: 1200
Here is what I use:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (!numberFormatter) {
numberFormatter = [[NSNumberFormatter alloc]init];
//[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
}
NSNumber *test = [numberFormatter numberFromString:[self.text stringByAppendingString: string]]; // in case we entered two decimals
return (test != nil);
}
Upvotes: 8