如何动态格式化数字以在UITextField条目中包含逗号?

时间:2014-12-05 04:06:48

标签: ios objective-c

我希望在用户输入时动态地将逗号添加到我的数字UITextField条目中。

例如:123,45612,345,678,但不是123,45123,4567

当用户在Objective-C中键入数字时,如何自动附加逗号?

编辑:我也希望能够允许用户输入小数。

9 个答案:

答案 0 :(得分:16)

您可以使用NSNumberFormatterDecimalStyle来处理逗号格式,而不是在shouldChangeCharactersInRange:中自行插入逗号。即使它被称为"十进制"样式,它还插入逗号以适当地将数字组合成千位数字。

注意:为简化问题,我假设您只希望文本字段接受数字输入,我还会添加逻辑以限制用户输入数字。

编辑:我已根据OP的请求更新了处理小数的代码。

要在每个字符条目上使用NSNumberFormatterDecimalStyle格式,请尝试将其添加到shouldChangeCharactersInRange:委托方法中:

- (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;
}

答案 1 :(得分:9)

这是Swift 4中的一个版本。 我用它来表示整数,我没有用十进制数来检查。

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
    // e.g. "," 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.isEmpty { // pressed Backspace key
                totalTextWithoutGroupingSeparators.removeLast()
            }
            if let numberWithoutGroupingSeparator = formatter.number(from: totalTextWithoutGroupingSeparators),
                let formattedText = formatter.string(from: numberWithoutGroupingSeparator) {

                textField.text = formattedText
                return false
            }
        }
    }
    return true
}

此方法的一大优点是它使用当前语言环境(区域)中定义的分组分隔符,因为并非每个人都使用逗号作为分组分隔符。

使用0,退格键,但是,我再次没有使用小数进行测试。 如果您使用小数字进行处理,则可以自由地增强此代码。

示例:

  • 输入:“2” - &gt; “2”
  • 输入:“3” - &gt; “23”
  • 输入:“6” - &gt; “236”
  • 输入:“7” - &gt; “2367”
  • 输入:“0”3次 - &gt; “2367000”
  • 退格 - &gt; “236700”

开始0也有效:

  • 输入:“0” - &gt; “0”
  • 输入:“2” - &gt; “2”

答案 2 :(得分:5)

对于Lyndsey Scott's answer的Swift 4.0版本:

   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

    }

答案 3 :(得分:3)

使用分组属性格式化数字,如下所示。

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

上述代码的输出为

1,234,567.850

答案 4 :(得分:0)

使用UITextFieldDelegate方法:(您的视图控制器需要是文本字段的委托)

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

将字符添加到textField时,它将调用此方法。然后,您可以在任何地方插入逗号。

注意:人们可以将文本粘贴到文本字段,删除值,移动光标等,因此您需要考虑很多测试。

在SO上有很多类似的问题,例如: How to put comma and decimals in my UITextField dynamically?

Auto suggest in UITextfield with comma separation

答案 5 :(得分:0)

Windy请记住,逗号应该添加到数字本身,而不是用户必须输入它们。

第一

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

您必须自行更改以更改文本。并且将添加逗号的代码是

-(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;
}

答案 6 :(得分:0)

编辑请参阅Lindsey Scott的答案,了解更新的正确版本。

这是基于Lindsey Scott先前的回答,但更新为占小数点后输入的0:

- (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;
}

答案 7 :(得分:0)

这是swift 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!
    }
}

不要忘记添加 editingChanged 操作,如下所示:

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

答案 8 :(得分:0)

我还有一个。修复了一些本地配置的错误,小数点后为零

const window= new BrowserWindow({...});
window.setMenuBarVisibility(false);