How do you dynamically format a number to have commas in a UITextField entry?

前端 未结 9 1952
傲寒
傲寒 2020-12-08 17:42

I want to have commas dynamically added to my numeric UITextField entry while the user is typing.

For example: 123,456 and 12,345,678

相关标签:
9条回答
  • 2020-12-08 17:54

    Windy please keep in mind the commas should get add to the number itself, not like user has to enter them.

    First

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

    You have to change to change the Text yourself. And the Code that will add the commas is

    -(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 讨论(0)
  • 2020-12-08 18:02

    For Swift 4.0 Version of Lyndsey Scott's 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's 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's numeric, or if it's
            // a backspace, or if it's 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
    
        }
    
    0 讨论(0)
  • 2020-12-08 18:05

    Use the UITextFieldDelegate method: (your view controller needs to be a delegate of the textfield)

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

    When a character is added to the textField, it will call this method. You can then insert commas wherever you want.

    Note: people can paste text into textfields, delete values, move the cursor, etc. so you have a lot of tests to consider.

    There are lots of similar questions on SO, e.g. How to put comma and decimals in my UITextField dynamically?

    Auto suggest in UITextfield with comma separation

    etc

    0 讨论(0)
  • 2020-12-08 18:06

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

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

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    
        if (textField == _questionPoolNameTextField) {
            return YES;
        }
    
        //For 0's 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's numeric...
        NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
        NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
        bool isNumeric = [string isEqualToString:filtered];
    
        // Then if the replacement string's numeric, or if it's
        // a backspace, or if it's 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 讨论(0)
  • 2020-12-08 18:07

    Instead of inserting the commas on your own in shouldChangeCharactersInRange:, you can use an NSNumberFormatterDecimalStyle to handle the comma formatting for you. Even though it's called "decimal" style, it also inserts commas to appropriately group numbers into their thousands digits.

    Note: To simplify matters, I'll assume you only want the text field to accept numeric entries and I'll also add logic to limit the user's input to numbers.

    Edit: I've updated the code to handle decimals also as per the OP's request.

    To utilize NSNumberFormatterDecimalStyle's formatting upon every 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's numeric...
        NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
        NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
        bool isNumeric = [string isEqualToString:filtered];
    
        // Then if the replacement string's numeric, or if it's 
        // a backspace, or if it's 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;
    }
    
    0 讨论(0)
  • 2020-12-08 18:11

    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];
    

    Output for the above code is

    1,234,567.850
    
    0 讨论(0)
提交回复
热议问题