Numbers separated by commas in UITextField not working - ios

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: 4
And 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).

Related

How to add commas automatically for every 3 numbers while user input the text field - iOS Objective C [duplicate]

This question already has answers here:
How do you dynamically format a number to have commas in a UITextField entry?
(9 answers)
Closed 5 years ago.
How to add commas for every 3 numbers while user inputting the text field and also display the number with commas on the label?
I am using this function but it does not work.
- (void)commaFormatter
{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setGroupingSeparator:#","];
[numberFormatter setGroupingSize:3];
[numberFormatter setDecimalSeparator:#"."];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
}
If you want a number like 123,456,789,5 then use shouldChangeCharactersInRange delegate method and write below code inside it.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *strTemp = textField.text;
strTemp = [textField.text stringByReplacingOccurrencesOfString:#"," withString:#""];
if (strTemp.length%3==0&&![string isEqualToString:#""]&&textField.text.length!=0&&![[textField.text substringWithRange:NSMakeRange(textField.text.length-1, 1)] isEqualToString:#","]) {
_txtField.text = [_txtField.text stringByAppendingString:#","];
}
return YES;
}

add prefix to UITextField

I want to add prefix of UITextfield text. The UITextfield text length less than 7. How many characters are less than 7, that all replace with zeros.
If text is "1234", add prefix like "0001234".
If text is "12345", add prefix like "0012345".
If text is "123", add prefix like "0000123".
can any one suggest me, how to implement.
It sounds like what we actually want is a numbers-only string that is always 7-characters long, with the left-most characters filled in with padded zeros for anything the user has not entered, correct?
So, we need a handful of methods to make this as easy as possible.
First, this one doesn't make sense right now, but we want a method to remove the zeros we padded at the front (it'll make sense later).
So, borrowing from this Stack Overflow answer...
- (NSString *)stringByRemovingPaddedZeros:(NSString *)string {
NSRange range = [string rangeOfString:#"^0*" options:NSRegularExpressionSearch];
return [string stringByReplacingCharactersInRange:range withString:#""];
}
And we'll borrow from Ilesh's answer for adding the padded zeros:
- (NSString *)stringByAddingPaddedZeros:(NSString *)string padLength:(NSInteger)length {
NSString *padding = [#"" stringByPaddingToLength:(length - string.length) withString:#"0" startingAtIndex:0];
return [NSString stringWithFormat:#"%#%#", padding, string];
}
So now we can go back and forth between padded and unpadded strings, right?
So now, one last step, implementing shouldChangeCharactersInRange:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
newString = [self stringByRemovingPaddedZeros:newString];
newString = [self stringByAddedPaddedZeros:newString padLength:7];
textField.text = [newString subStringToIndex:7];
return NO;
}
We always return NO here, as we're setting the textField.text property manually. Now when there are 7 characters (and no leading zeros), the user can type no more. If there are 7 characters and the user hits backspace, they should all shift right one and a zero added to the front. If there are leading zeros at the front, typing characters should shift everything left and drop a leading zero, and add a new character to the front.
As an additional note, this code does not take care of verifying that the user is only entering digits. Some extra logic would be required for that. I'd simply recommend checking that the replacementString (string) is only digits before you get into any of the other code in shouldChangeCharactersInRange here.
Here printing textfield text on button click. Check the code inside the method.
- (IBAction)logTextFieldText:(id)sender
{
NSMutableString *str=[[NSMutableString alloc]init];
if (_txtf.text.length<7)
{
for (int i=0;i<7-_txtf.text.length; i++)
{
[str appendString:#"0"];
}
[str appendString:_txtf.text];
}
NSLog(#"final text is: %#",str);
}
Implement the UITextFieldDelegate method textFieldDidEndEditing: to pad the 0's in.
- (void)textFieldDidEndEditing:(nonnull UITextField *)textField
{
if (textField.text.length < 7) {
// Create a string of 0's to pad with
NSString *padding = [#"" stringByPaddingToLength:(7 - textField.text.length) withString:#"0" startingAtIndex:0];
NSMutableString *change = [textField.text mutableCopy];
// Insert the 0's string
[change insertString:padding atIndex:0];
textField.text = change;
}
}
If you want to fix the length of UITextField text than use this UITextField delegate method.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (self.txtGet.text.length>=7) {
return NO;
}
return YES;
}
and the completion editing (or done button ) you add this line in before using the UITextField value.
NSString *padding = [#"" stringByPaddingToLength:(7 - self.txtGet.text.length) withString:#"0" startingAtIndex:0];
NSMutableString *change = [self.txtGet.text mutableCopy];
// Insert the 0's string
[change insertString:padding atIndex:0];
self.txtGet.text = change;
I think its helpful to you. Thank you.

How do I enforce that an UITextView shows only lower-case letters? [duplicate]

This question already has answers here:
Converting all text to lower case in Objective-C
(3 answers)
Closed 7 years ago.
I'm working on a social script for iOS but i'll need my username login only be lowercase. I've got the string where lowercaseString needs to be into but I don't exactly know where.
So this is the code:
NSString *username = [self.usernameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];**
Where do I put the .lowercaseString for only lowercase login?
NSString *username = [self.usernameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].lowercaseString;
However, this only ensures that username is lowercase. To make sure that the UITextField contains only lowercase characters, you may do this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
NSRange upperCharRange;
upperCharRange = [string rangeOfCharacterFromSet:[NSCharacterSet uppercaseLetterCharacterSet]];
if (uppercaseCharRange.location != NSNotFound) {
textField.text = [textField.text stringByReplacingCharactersInRange:range
withString:[string lowercaseString]];
return NO;
}
return YES;
}
This method is only called if you add <UITextFieldDelegate> to the .h file of your class. You also need to set the delegate of your UITextField instance to self of your class instance, like so:
textField.delegate = (id <UITextFieldDelegate>)mainViewController;
You can put it after self.usernameField.text or after the ]]. There is not really any difference since lowerCase does not affect whitespaces or newline characters.
The only difference is that after trimming the string, the string might be shorter and therefore the transformation to a lower case string will take less time (not noticeably though).
Therefore I would propose adding it after ]]:
NSString *username = [self.usernameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].lowercaseString;

Formating a single textfield so that it display is different to all the others

How would i set the currency in a text field to display it as a localized currency, with a leading 0. If someone types in 16.25 pence it would be formated as 0.1625£ respectively. I am using delegation and formating all text fields so only numbers can be passed in, this field should also be localized.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // First, create the text that will end up in the input field if you'll return YES:
NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
// Now, validate the text and return NO if you don't like what it'll contain.
// You accomplish this by trying to convert it to a number and see if that worked.
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* resultingNumber = [numberFormatter numberFromString:resultString];
//[numberFormatter release];
return resultingNumber != nil;
I do not want this to change, as it formats all my fields. Just want textField1 to have the relevant format,how would i go about doing this, i think it lies in viewdidload method and setting the text property to be localized to a floating point, but i cant seem to work out how to do it.
You can specify which textField you want to format in the delegate method above.
if (textField == textField1) {
// Do Something....
} else {
// Do whatever you want with the other text fields
}
For floating point formatting, use something like this -
[myTextField setText:[NSString stringWithFormat:#"%.2f", myFloat]];
(void)textFieldDidEndEditing:(UITextField *)textField
{
if (textfield1) {
NSString *txt = self.textfield1.text;
double num1 = [txt doubleValue];
double tCost = num1 /100;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *numberAsString = [numberFormatter stringFromNumber:[NSNumber numberWithFloat:tCost]];
self.textfield1.text = [NSString stringWithFormat:#"%#",numberAsString];
}
}

Getting an IndexOutofBoundsException when implementing delegate method shouldChangeCharactersInRange in iOS

I have a UITextField in my application that I want to function like a calculator. I need it to have the default value of 0.00, and as the user enters digits, the numbers move from right to left, replacing the zeroes in 0.00 one digit at a time, and the application should be smart enough to add commas (,) after every three digits. To do this, I am implementing the delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {}
as follows:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if([[string stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]]
isEqualToString:#""])
return YES;
NSString *previousValue = [[[textField.text stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] stringByReplacingOccurrencesOfString:#"." withString:#""] stringByReplacingOccurrencesOfString:#"," withString:#""];
string = [string stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
NSString *modifiedValue = [NSString stringWithFormat:#"%#%#",previousValue,string];
modifiedValue = [NSString stringWithFormat:#"%#.%#",[modifiedValue substringToIndex:modifiedValue.length-2],[modifiedValue substringFromIndex:modifiedValue.length-2]];//this is the line that is causing the error
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
modifiedValue = [formatter stringFromNumber:[NSNumber numberWithFloat:[modifiedValue floatValue]]];
textField.text = modifiedValue;
return NO;
}
However, I am getting the following error:
'NSRangeException', reason: '*** -[__NSCFString substringToIndex:]: Range or index out of bounds'
This error was thrown the moment I tried to enter a number in the textfield. Can anyone see what I am doing wrong?
Thanks in advance to all who reply.
Yeah, this bit right here:
[modifiedValue substringToIndex:modifiedValue.length-2]
seems to assume that the length of the string is at least 2.
Which is probably isn't, at least when the user is typing his/her first character into an empty text field.
How about putting a length check around the whole thing, only doing the guts of the "shouldChangeCharactersInRange" method if the length is greater than two characters?

Resources