0

经过一天多的时间来解决这个问题,我会看看我是否能得到一些帮助。这个问题之前或多或少地被问过,但似乎没有人给出完整的答案,所以希望我们现在能得到它。

使用 UILabel 和 UITextView(带数字键盘)我想实现一种类似于 ATM 的行为,让用户只需键入数字并将其格式化为标签中的货币。这里基本上概述了这个想法:

输入带小数点的数值的最佳方法是什么?

唯一的问题是它从来没有明确说明我们如何才能在文本字段中使用像 123 这样的整数并在标签中显示为 $1.23 或 123¥ 等。有人有这样做的代码吗?

4

4 回答 4

3

我找到了解决方案,根据这个问题的目的,我将为将来遇到此问题的人提供完整的答案。首先,我创建了一个名为 NumberFormatting 的新 Helper 类并创建了两个方法。

//
//  NumberFormatting.h
//  Created by Noah Hendrix on 12/26/09.
//

#import <Foundation/Foundation.h>


@interface NumberFormatting : NSObject {

}

-(NSString *)stringToCurrency:(NSString *)aString;
-(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal;

@end

这是实现文件:

//
//  NumberFormatting.m
//  Created by Noah Hendrix on 12/26/09.
//

#import "NumberFormatting.h"


@implementation NumberFormatting

  -(NSString *)stringToCurrency:(NSString *)aString {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if ([aString length] == 0)
      aString = @"0";

    //convert the integer value of the price to a decimal number i.e. 123 = 1.23
    //[currencyFormatter maximumFractionDigits] gives number of decimal places we need to have
    //multiply by -1 so the decimal moves inward
    //we are only dealing with positive values so the number is not negative
    NSDecimalNumber *value  = [NSDecimalNumber decimalNumberWithMantissa:[aString integerValue]
                                                                exponent:(-1 * [currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [currencyFormatter stringFromNumber:value];
  }

  -(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if (aDecimal == nil)
      aDecimal = [NSDecimalNumber zero];

    NSDecimalNumber *price  = [NSDecimalNumber decimalNumberWithMantissa:[aDecimal integerValue]
                                                                exponent:([currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [price stringValue];
  }

@end

第一种方法 stringToCurrency 将采用一个整数(在本例中从文本字段传入),并通过根据用户区域设置移动小数点将其转换为十进制值。然后它返回一个使用 NSNumberFormatter 格式化为货币的字符串表示形式。

第二种方法相反,它采用类似 1.23 的值,并使用类似的方法将其转换回 123。

这是我如何使用它的示例

...
self.accountBalanceCell.textField.text  = [[NumberFormatting alloc] decimalToIntString:account.accountBalance];
...
[self.accountBalanceCell.textField addTarget:self
                                            action:@selector(updateBalance:)
                                  forControlEvents:UIControlEventEditingChanged];

这里我们将文本字段的值设置为数据存储中的十进制值,然后我们设置一个观察者来观察文本字段的变化并运行方法 updateBalance

- (void)updateBalance:(id)sender {
  UILabel *balanceLabel = (UILabel *)[accountBalanceCell.contentView viewWithTag:1000];
  NSString *value       = ((UITextField *)sender).text;
  balanceLabel.text     = [[NumberFormatting alloc] stringToCurrency:value];
}

它只是获取文本字段值并通过上述 stringToCurrency 方法运行它。

对我来说,这似乎很骇人听闻,所以如果您有兴趣使用它,请花点时间查看并清理它。我还注意到它会破坏大值。

于 2009-12-27T22:14:00.827 回答
2

看看NSNumberFormatter,它将根据当前或指定的语言环境格式化数字数据。

于 2009-12-25T08:37:35.197 回答
0

由于我仍然没有看到这个问题的正确答案,我将在不使用 NSScanner 的情况下分享我的解决方案(扫描仪似乎对我不起作用)。是“什么是输入带小数点数值的最佳方法? ”和“从 NSString 中删除除数字之外的所有数字”答案的组合。

首先,我在 UITextField 中呈现一个带有用户本地货币设置的 NSString,如下所示:

//currencyFormatter is of type NSNumberFormatter
if (currencyFormatter == nil) {
    currencyFormatter = [[NSNumberFormatter alloc] init];
    [currencyFormatter setLocale:[NSLocale currentLocale]];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    //[currencyFormatter setGeneratesDecimalNumbers:YES];
    decimalSeperator = [currencyFormatter decimalSeparator];  //NSString
    currencyScale = [currencyFormatter maximumFractionDigits]; //short
    //[currencyFormatter release]; don't forget to release the Formatter at one point

}


//costField is of type UITextField
NSDecimalNumber *nullValue = [NSDecimalNumber decimalNumberWithMantissa:0 exponent:currencyScale isNegative:NO];
[costField setText:[currencyFormatter stringFromNumber:nullValue]];

您可以在 viewControllers 方法 viewDidLoad: 中执行此操作。根据用户设置,将显示如下字符串:$0.00(用于美国本地设置)。根据您在此处的情况,您可能希望从数据模型中呈现一个值。

当用户在文本字段内触摸时,我将显示一个键盘类型:

costField.keyboardType = UIKeyboardTypeDecimalPad; 

这可以防止用户输入除数字之外的任何其他内容。

在下面的 UITextField 的委托方法中,我将字符串分开以仅获取数字(这里我避免使用 NSScanner)。这是可能的,因为我知道通过使用之前指定的 'currencyScale' 值来设置小数点分隔符:

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

if (textField == costField) {

    //if for what ever reason ther currency scale is not available set it to 2
    //which is the most common scale value 
    if (!currencyScale) {
        currencyScale = 2;
    }

    // separate string from all but numbers
    // https://stackoverflow.com/questions/1129521/remove-all-but-numbers-from-nsstring/1163595#1163595
    NSString *aString = [textField text];
    NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
    for (int i=0; i<[aString length]; i++) {
        if (isdigit([aString characterAtIndex:i])) {
            [strippedString appendFormat:@"%c",[aString characterAtIndex:i]];
        }
    }

    //add the newly entered character as a number
    // https://stackoverflow.com/questions/276382/what-is-the-best-way-to-enter-numeric-values-with-decimal-points/2636699#2636699
    double cents = [strippedString doubleValue];
     NSLog(@"Cents:%f ",[strippedString doubleValue]);
    if ([string length]) {
        for (size_t i = 0; i < [string length]; i++) {
            unichar c = [string characterAtIndex:i];
            if (isnumber(c)) {
                cents *= 10;        //multiply by 10 to add a 0 at the end
                cents += c - '0';  // makes a number out of the charactor and replace the 0 (see ASCII Table)
            }            
        }
    } 
    else {
        // back Space if the user delete a number
        cents = floor(cents / 10);
    }

    //like this you could save the value as a NSDecimalNumber in your data model
    //costPerHour is of type NSDecimalNumber
    self.costPerHour = [NSDecimalNumber decimalNumberWithMantissa:cents exponent:-currencyScale isNegative:NO];

    //creat the string with the currency symbol and the currency separator
    [textField setText:[currencyFormatter stringFromNumber:costPerHour]];

    return NO;
    }

return YES;
}

这样用户输入的货币永远是正确的,无需检查。无论选择哪种货币设置,这始终是格式正确的货币。

于 2011-07-15T13:04:07.893 回答
0

我不太喜欢这里现有的答案,所以我结合了几种技术。我使用带有数字键盘的隐藏 UITextField 进行输入,并使用可见的 UILabel 进行格式化。

我必须拥有可以保留所有内容的属性:

@property (weak, nonatomic) IBOutlet UILabel *amountLabel;
@property (weak, nonatomic) IBOutlet UITextField *amountText;
@property (retain, nonatomic) NSDecimalNumber *amount;

我有金额和 NSNumberFormatter 作为 ivars:

NSDecimalNumber *amount_;
NSNumberFormatter *formatter;

我在初始化时设置了我的格式化程序:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Custom initialization
        formatter = [NSNumberFormatter new];
        formatter.numberStyle = NSNumberFormatterCurrencyStyle;
    }
    return self;
}

这是我用来验证输入的代码,将其转换为

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *asText = [textField.text stringByReplacingCharactersInRange:range withString:string];
    if ([asText length] == 0) {
        [self setAmount:[NSDecimalNumber zero]];
        return YES;
    }
    // We just want digits so cast the string to an integer then compare it
    // to itself. If it's unchanged then it's workable.
    NSInteger asInteger = [asText integerValue];
    NSNumber *asNumber = [NSNumber numberWithInteger:asInteger];
    if ([[asNumber stringValue] isEqualToString:asText]) {
        // Convert it to a decimal and shift it over by the fractional part.
        NSDecimalNumber *newAmount = [NSDecimalNumber decimalNumberWithDecimal:[asNumber decimalValue]];
        [self setAmount:[newAmount decimalNumberByMultiplyingByPowerOf10:-formatter.maximumFractionDigits]];
        return YES;
    }
    return NO;
}

我有这个设置器,而不是处理格式化标签并启用完成按钮:

-(void)setAmount:(NSDecimalNumber *)amount
{
    amount_ = amount;
    amountLabel.text = [formatter stringFromNumber:amount];
    self.navigationItem.rightBarButtonItem.enabled = [self isValid];
}
于 2012-07-23T16:14:38.677 回答