尝试将UITextField格式化为仅适用于iOS中的数字输入的货币计算器

时间:2013-03-05 06:20:59

标签: ios uitextfield currency nsnumberformatter

我的应用程序中有一个UITextField,它应该只接收来自用户的数字输入。这个数字输入应该代表货币(即只有两个小数位),当没有输入任何内容时,默认值 0.00 。我还希望在最左边有一个“$”符号,数字右对齐,这样数字从右向左移动,如下所示:

e.g。输入数字“1234.56”

1。 $ 0.00

2。 $ 0.01

第3。 $ 0.12

4。 $ 1.23

5。 $ 12.34

6。 $ 123.45

7。 $ 1,234.56

8。等等...

我将UITextField右对齐,以便它已将数字从右侧移到左侧。但是,我需要将“$”放在 UITextField 中,我希望将默认的 0.00 值修改为输入的数字用户一次一位数。用户不必输入小数点,因为它应该已经在保持其位置的文本字段中。然后,我希望该号码能够自动输入“,”以分隔每三位数字。我希望应用程序执行此操作用户输入数字,并且在输入所有内容后不再格式化。我该怎么做?我见过很多人说我要使用NSNumberFormatter,但我想知道如何将它与UITextField一起使用,以便它可以动态格式化数字文本,如如上所述?

我发现在StackOverflow上发布了以下问题:

What is the best way to enter numeric values with decimal points?

但我想知道如何将其作为我问题的解决方案实际加​​入。

5 个答案:

答案 0 :(得分:14)

这是一个很好的方法。请记住在viewDidLoad方法中将UITextField设置为self,并且头文件必须符合UITextFieldDelegate协议

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

    NSString *cleanCentString = [[textField.text componentsSeparatedByCharactersInSet: [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""];
    NSInteger centValue = [cleanCentString intValue];
    NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
    NSNumber *myNumber = [f numberFromString:cleanCentString];
    NSNumber *result;

    if([textField.text length] < 16){
        if (string.length > 0)
        {
            centValue = centValue * 10 + [string intValue];
            double intermediate = [myNumber doubleValue] * 10 +  [[f numberFromString:string] doubleValue];
           result = [[NSNumber alloc] initWithDouble:intermediate];
        }
        else
        {
            centValue = centValue / 10;
            double intermediate = [myNumber doubleValue]/10;
            result = [[NSNumber alloc] initWithDouble:intermediate];
        }

        myNumber = result;
         NSLog(@"%ld ++++ %@", (long)centValue, myNumber);
            NSNumber *formatedValue;
            formatedValue = [[NSNumber alloc] initWithDouble:[myNumber doubleValue]/ 100.0f];
            NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
            [_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
            textField.text = [_currencyFormatter stringFromNumber:formatedValue];
            return NO;
    }else{

        NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
        [_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        textField.text = [_currencyFormatter stringFromNumber:00];

        UIAlertView *alert = [[UIAlertView alloc]initWithTitle: @"Deposit Amount Limit"
                                                       message: @"You've exceeded the deposit amount limit. Kindly re-input amount"
                                                      delegate: self
                                             cancelButtonTitle:@"Cancel"
                                             otherButtonTitles:@"OK",nil];

        [alert show];
        return NO;
    }
    return YES;
}

答案 1 :(得分:5)

更新了SWIFT 3的答案

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = 2
        formatter.maximumFractionDigits = 2

        if string.characters.count > 0 {
            amountTypedString += string
            let decNumber = NSDecimalNumber(string: amountTypedString).multiplying(by: 0.01)
            let newString = "$" + formatter.string(from: decNumber)!
            textField.text = newString
        } else {
            amountTypedString = String(amountTypedString.characters.dropLast())
            if amountTypedString.characters.count > 0 {
                let decNumber = NSDecimalNumber(string: amountTypedString).multiplying(by: 0.01)
                let newString = "$" +  formatter.string(from: decNumber)!
                textField.text = newString
            } else {
                textField.text = "$0.00"
            }

        }
        return false

    }

    func textFieldShouldClear(_ textField: UITextField) -> Bool {
        amountTypedString = ""
        return true
    }

答案 2 :(得分:3)

这是我在Swift中的解决方案。我的方法是跟踪输入的数字并将其乘以0.01,并使用NSNumberFormatter将结果数设置为2个小数点。请注意,我将文本字段键盘设置为数字键盘。

amountTextfield?.keyboardType = UIKeyboardType.NumberPad

var amountTypedString = ""

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    let formatter = NSNumberFormatter()
    formatter.minimumFractionDigits = 2
    formatter.maximumFractionDigits = 2

    if string.characters.count > 0 {
        amountTypedString += string
        let decNumber = NSDecimalNumber(float: Float(amountTypedString)!).decimalNumberByMultiplyingBy(0.01)
        let newString = "$" + formatter.stringFromNumber(decNumber)!
        textfield.text = newString
    } else {
        amountTypedString = String(amountTypedString.characters.dropLast())
        if amountTypedString.characters.count > 0 {
            let decNumber = NSDecimalNumber(float: Float(amountTypedString)!).decimalNumberByMultiplyingBy(0.01)
            let newString = "$" +  formatter.stringFromNumber(decNumber)!
            textfield.text = newString
        } else {
            textfield.text = "$0.00"
        }

    }
    return false

}

func textFieldShouldClear(textField: UITextField) -> Bool {
    amountTypedString = ""
    return true
}

答案 3 :(得分:1)

您可能需要查看UITextFieldDelegate协议。通过将某些东西(通常是您的ViewController类)指定为UITextField的委托,您将能够从控件接收交互式文本输入事件。特别是:

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

通过从该方法返回NO,可以防止文本字段应用用户按下的键。

但是,即使您返回NO,也没有什么可以阻止您使用传递给委托方法的信息来自行处理代码中的文本字段内容。

以伪代码形式:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (string-contains-number) {
        alter textfield.text to be what it should be now, adding the number;
    }
    else {
        string contains something you don't wan the user typing, so ignore it.
    }

    // Tell iOS not to apply the user's change (since you just did by 
    // updating the text yourself:
    return NO;
}

免责声明:我没有编写实际的代码进行测试,因此更改此委托方法中的代码可能导致另一个shouldChangeCharactersInRange:消息被触发。不过,我不相信这种情况。当您在代码中更改文本时,我不相信委托事件会触发。

这显然不如已经实现了数字文本输入框的所有规则的自定义控件(我现在有多年的Visual Basic编程闪回...)。但是我不知道有人写过这样的控件并且是开源的。

答案 4 :(得分:0)

我从julien那里得到了答案并对其进行了修改,以便支持其他具有不同货币格式的区域设置。我还存储了数字格式化程序以供​​重用,因此每次都不会创建它们,这是一项昂贵的操作。

忽略任何会导致存储值溢出的输入来处理溢出。

此解决方案假定文本仅在文本字段的末尾输入,因此无论文本光标在输入之前的位置如何,都只会在结尾处进行操作。

let outputFormatter: NSNumberFormatter = {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    if formatter.maximumFractionDigits > 0 {
        formatter.multiplier = pow(10, -CGFloat(formatter.maximumFractionDigits))
    }
    return formatter
}()

let inputFormatter: NSNumberFormatter = {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .DecimalStyle
    return formatter
}()

private var value: UInt = 0

var currencyValue: NSDecimalNumber {
    let exponent = Int16(truncatingBitPattern: outputFormatter.maximumFractionDigits)
    return NSDecimalNumber(mantissa: UInt64(value), exponent: -exponent, isNegative: false)
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string.isEmpty {
        /* User pressed backspace, shift right one space. */
        value /= 10
    } else if let number = inputFormatter.numberFromString(string)?.unsignedIntegerValue {
        /* User entered a number, shift left one space and add. */
        let shiftedValue = UInt.multiplyWithOverflow(value, 10)
        let addedValue = UInt.addWithOverflow(shiftedValue.0, number)
        if !shiftedValue.overflow && !addedValue.overflow {
            value = addedValue.0
        }
    }

    textField.text = outputFormatter.stringFromNumber(NSDecimalNumber(unsignedInteger: value))
    return false
}

func textFieldShouldClear(textField: UITextField) -> Bool {
    value = 0
    return true
}

在有各种区域设置的游乐场中使用此功能,我these results (抱歉,还不能直接嵌入)。