How do you dynamically format a number with commas in a UITextField record?

I want commas to be dynamically added to my numeric UITextField record when the user types.

For example: 123,456 and 12,345,678 , but not like this 123,45 or 123,4567 .

How to automatically add commas when a user enters a number in Objective-C?

Edit: I would also like to allow the user to enter decimals.

+7
source share
8 answers

Instead of inserting commas yourself in shouldChangeCharactersInRange: you can use NSNumberFormatterDecimalStyle to handle comma formatting. Despite the fact that it is called the โ€œdecimalโ€ style, it also inserts commas to appropriately group numbers into their thousands of digits.

Note. To make things easier, suppose you want the text field to accept numerical entries, and I will also add logic to limit the user input for numbers.

Edit: I updated the code to handle decimals also as requested by OP.

To use the NSNumberFormatterDecimalStyle formatting for each character entry, try adding this to your shouldChangeCharactersInRange: delegate method::

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (([string isEqualToString:@"0"] || [string isEqualToString:@""]) && [textField.text rangeOfString:@"."].location < range.location) { return YES; } // First check whether the replacement string numeric... NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""]; bool isNumeric = [string isEqualToString:filtered]; // Then if the replacement string numeric, or if it // a backspace, or if it a decimal point and the text // field doesn't already contain a decimal point, // reformat the new complete number using // NSNumberFormatterDecimalStyle if (isNumeric || [string isEqualToString:@""] || ([string isEqualToString:@"."] && [textField.text rangeOfString:@"."].location == NSNotFound)) { // Create the decimal style formatter NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; [formatter setMaximumFractionDigits:10]; // Combine the new text with the old; then remove any // commas from the textField before formatting NSString *combinedText = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSString *numberWithoutCommas = [combinedText stringByReplacingOccurrencesOfString:@"," withString:@""]; NSNumber *number = [formatter numberFromString:numberWithoutCommas]; NSString *formattedString = [formatter stringFromNumber:number]; // If the last entry was a decimal or a zero after a decimal, // re-add it here because the formatter will naturally remove // it. if ([string isEqualToString:@"."] && range.location == textField.text.length) { formattedString = [formattedString stringByAppendingString:@"."]; } textField.text = formattedString; } // Return no, because either the replacement string is not // valid or it is and the textfield has already been updated // accordingly return NO; } 
+15
source

Here is the version in Swift 3. I used it for integers, I did not check decimal numbers.

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Uses the number format corresponding to your Locale let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.locale = Locale.current formatter.maximumFractionDigits = 0 // Uses the grouping separator corresponding to your Locale // eg "," in the US, a space in France, and so on if let groupingSeparator = formatter.groupingSeparator { if string == groupingSeparator { return true } if let textWithoutGroupingSeparator = textField.text?.replacingOccurrences(of: groupingSeparator, with: "") { var totalTextWithoutGroupingSeparators = textWithoutGroupingSeparator + string if string == "" { // pressed Backspace key totalTextWithoutGroupingSeparators.characters.removeLast() } if let numberWithoutGroupingSeparator = formatter.number(from: totalTextWithoutGroupingSeparators), let formattedText = formatter.string(from: numberWithoutGroupingSeparator) { textField.text = formattedText return false } } } return true } 

The great advantage of this method is that it uses the grouping delimiter defined in your current locale (region), since not everyone uses a comma as the grouping delimiter.

Works with 0, backspace, but, again, I have not tested it with decimal places. You can improve this code if you developed it with decimal places.

Examples:

  • Enter: "2" โ†’ "2"
  • Enter: "3" โ†’ "23"
  • Enter: "6" โ†’ "236"
  • Enter: "7" โ†’ "2,367"
  • Enter: "0" 3 times โ†’ "2,367,000"
  • Backspace โ†’ "236,700"

Starting 0 also works:

  • Enter: "0" โ†’ "0"
  • Enter: "2" โ†’ "2"
+6
source

Format the number with grouping attributes as shown here.

 NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; [numberFormatter setGroupingSeparator:@","]; [numberFormatter setGroupingSize:3]; [numberFormatter setDecimalSeparator:@"."]; [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; [numberFormatter setMaximumFractionDigits:3]; [numberFormatter setMinimumFractionDigits:3]; 

The output for the above code

 1,234,567.850 
+3
source

For Swift 4.0 version Lyndsey Scott answer :

  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if ((string == "0" || string == "") && (textField.text! as NSString).range(of: ".").location < range.location) { return true } // First check whether the replacement string numeric... let cs = NSCharacterSet(charactersIn: "0123456789.").inverted let filtered = string.components(separatedBy: cs) let component = filtered.joined(separator: "") let isNumeric = string == component // Then if the replacement string numeric, or if it's // a backspace, or if it a decimal point and the text // field doesn't already contain a decimal point, // reformat the new complete number using if isNumeric { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.maximumFractionDigits = 8 // Combine the new text with the old; then remove any // commas from the textField before formatting let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string) let numberWithOutCommas = newString.replacingOccurrences(of: ",", with: "") let number = formatter.number(from: numberWithOutCommas) if number != nil { var formattedString = formatter.string(from: number!) // If the last entry was a decimal or a zero after a decimal, // re-add it here because the formatter will naturally remove // it. if string == "." && range.location == textField.text?.count { formattedString = formattedString?.appending(".") } textField.text = formattedString } else { textField.text = nil } } return false } 
+3
source

Use the UITextFieldDelegate: method (your view manager should be a text field delegate)

 -(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

When a character is added to textField, it calls this method. Then you can insert commas wherever you want.

Note: people can insert text into text fields, delete values, move the cursor, etc., so you have many tests to consider.

There are many similar questions on SO, for example. How to add comma and decimals in my UITextField dynamically?

Automatic suggestion in UITextfield with a comma section

etc.

0
source

Windy, please keep in mind that commas should add to the number itself, and not how the user should enter them.

First

 // Add a "textFieldDidChange" notification method to the text field control. [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; 

You must change to change the text yourself. The code that will add the comma will be

 -(void) textFieldDidChange { NSNumberFormatter *formatter = [NSNumberFormatter new]; [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; // this line is important! NSString *formatted = [formatter stringFromNumber:[NSNumber numberWithInteger:2000000]]; NSLog(@"the Formatted String is %@",formatted); textField.text = formatted; } 
0
source

EDIT See Lindsey Scott's review for an updated, correct version.

This is based on Lindsay Scott's previous answer, but updated to account for the 0 entered after the decimal:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (textField == _questionPoolNameTextField) { return YES; } //For 0 after the decimal point: if ([string isEqualToString:@"0"] && (0 <= (int)[textField.text rangeOfString:@"."].location)) { if ([textField.text rangeOfString:@"."].location < range.location) { return YES; } } // First check whether the replacement string numeric... NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""]; bool isNumeric = [string isEqualToString:filtered]; // Then if the replacement string numeric, or if it's // a backspace, or if it a decimal point and the text // field doesn't already contain a decimal point, // reformat the new complete number using // NSNumberFormatterDecimalStyle if (isNumeric || [string isEqualToString:@""] || ([string isEqualToString:@"."] && [textField.text rangeOfString:@"."].location == NSNotFound)) { NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; [numberFormatter setGroupingSeparator:@","]; [numberFormatter setGroupingSize:3]; [numberFormatter setDecimalSeparator:@"."]; [numberFormatter setMaximumFractionDigits:20]; [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; // Combine the new text with the old; then remove any // commas from the textField before formatting NSString *combinedText = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSString *numberWithoutCommas = [combinedText stringByReplacingOccurrencesOfString:@"," withString:@""]; NSNumber *number = [numberFormatter numberFromString:numberWithoutCommas]; NSString *formattedString = [numberFormatter stringFromNumber:number]; // If the last entry was a decimal at the end of the // re-add it here because the formatter will naturally // remove it. if ([string isEqualToString:@"."] && range.location == textField.text.length) { formattedString = [formattedString stringByAppendingString:@"."]; } textField.text = formattedString; } // Return no, because either the replacement string is not // valid or it is and the textfield has already been updated // accordingly return NO; } 
0
source

Here is the solution in quick 4.

  @objc func textFieldValDidChange(_ textField: UITextField) { let formatter = NumberFormatter() formatter.numberStyle = NumberFormatter.Style.decimal if textField.text!.count >= 1 { let number = Double(bottomView.balanceTxtField.text!.replacingOccurrences(of: ",", with: "")) let result = formatter.string(from: NSNumber(value: number!)) textField.text = result! } } 

Remember to add the editChanged action as shown below:

 textField.addTarget(self, action:#selector(ViewController.textFieldValDidChange), for: .editingChanged) 
0
source

Source: https://habr.com/ru/post/1208400/


All Articles