在Cocoa挣扎着货币

时间:2009-02-27 01:45:23

标签: cocoa cocoa-touch uitextfield currency

我正在尝试做一些我认为相当简单的事情:让用户输入一个美元金额,将该金额存储在NSNumber(NSDecimalNumber?)中,然后再显示格式化为货币的金额。

我的麻烦不在于setNumberStyle:NSNumberFormatterCurrencyStyle并将浮动显示为货币。问题更多的是所述numberFormatter如何与这个UITextField一起工作。我可以找到一些例子。 This thread从11月开始,this one给了我一些想法,但给我留下了更多问题。

我正在使用UIKeyboardTypeNumberPad键盘,并了解我应该在显示的字段中显示$ 0.00(或任何本地货币格式),然后当用户输入数字以移动小数位时:

  • 以显示$ 0.00
  • 开头
  • 点击2键:显示$ 0.02
  • 点按5键:显示$ 0.25
  • 点按4键:显示$ 2.54
  • 点击3键:显示$ 25.43

然后[numberFormatter numberFromString:textField.text]应该给我一个值,我可以存储在我的NSNumber变量中。

可悲的是,我仍然在苦苦挣扎:这真的是最好/最简单的方法吗?如果是这样,也许有人可以帮助我实施?我觉得UITextField可能需要一个代理响应每个按键,但不知道什么,在哪里以及如何实现它?!任何示例代码?我非常感谢!我搜索过高低......

Edit1:所以我正在研究NSFormatter的 stringForObjectValue:以及我能找到的最接近benzado建议的内容: UITextViewTextDidChangeNotification 。真的很难在其中任何一个上找到示例代码...所以,如果你知道在哪里看,请告诉我?

7 个答案:

答案 0 :(得分:10)

我的解决方案:


- (BOOL)textField:(UITextField *)textField
    shouldChangeCharactersInRange:(NSRange)range 
    replacementString:(NSString *)string
{
  // Clear all characters that are not numbers
  // (like currency symbols or dividers)
  NSString *cleanCentString = [[textField.text
    componentsSeparatedByCharactersInSet:
    [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
      componentsJoinedByString:@""];
  // Parse final integer value
  NSInteger centAmount = cleanCentString.integerValue;
  // Check the user input
  if (string.length > 0)
  {
    // Digit added
    centAmount = centAmount * 10 + string.integerValue;
  }
  else
  {
    // Digit deleted
    centAmount = centAmount / 10;
  }
  // Update call amount value
  [_amount release];
  _amount = [[NSNumber alloc] initWithFloat:(float)centAmount / 100.0f];
  // Write amount with currency symbols to the textfield
  NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
  [_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
  [_currencyFormatter setCurrencyCode:@"USD"];
  [_currencyFormatter setNegativeFormat:@"-¤#,##0.00"];
  textField.text = [_currencyFormatter stringFromNumber:_amount];
  [_currencyFormatter release]
  // Since we already wrote our changes to the textfield
  // we don't want to change the textfield again
  return NO;
}

答案 1 :(得分:3)

这是我现在必须写的那个粗略的攻击计划。诀窍是输入隐藏的UITextField并使用格式化的值更新UILabel作为用户输入。

  1. 创建一个UITextField,使其隐藏,为其指定一个委托,然后将其作为召唤键盘的第一个响应者。
  2. 在您的委托中,通过获取文本字段的新值并将其转换为数字来响应textDidChange:消息(懒得查找确切的名称)。确保空字符串转换为零。
  3. 通过格式化程序运行该号码,并使用该格式化的货币值更新UILabel。
  4. 在每次按键时,标签都会更新,因此当用户真正编辑隐藏文本字段时,用户会觉得她正在编辑格式化的值。鬼鬼祟祟!

答案 2 :(得分:1)

嗯,我认为这样更好:

- (void)viewWillDisappear:(BOOL)animated{ [[NSNotificationCenter defaultCenter] removeObserver:self  name:UITextFieldTextDidChangeNotification object:nil]; }

-(void)viewDidAppear:(BOOL)animated{
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChanged:) name:UITextFieldTextDidChangeNotification object:nil];
}

-(void)textDidChanged:(NSNotification *)notification{
 [[NSNotificationCenter defaultCenter] removeObserver:self  name:UITextFieldTextDidChangeNotification object:nil];
 UITextField * textField= [notification object];
 NSString * sinPesos= [textField.text stringByReplacingOccurrencesOfString:@"$" withString:@""];
 NSString * sinPuntos= [sinPesos stringByReplacingOccurrencesOfString:@"." withString:@""];

 float monto = [sinPuntos floatValue]; 

 monto= monto/100;

 NSString * cardText= [[self montoFormatter] stringFromNumber:[NSNumber numberWithDouble:monto]]; 

 textField.text = ([cardText isEqualToString: @"0"] ? @"":cardText);
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChanged:) name:UITextFieldTextDidChangeNotification object:nil];
} 

-(NSNumberFormatter *)montoFormatter{
 NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
 [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
 [numberFormatter setMaximumFractionDigits:2];
 return [numberFormatter autorelease];
}

尝试一下:)

答案 3 :(得分:1)

由于我很懒,我无法忍受我的输入重新格式化“帮我出去”,我说:

让他们输入一个十进制数字。当他们离开现场时,重新格式化。

答案 4 :(得分:0)

嗯,这有点晚了但我觉得无论如何我都会试一试。这可能是一种解决方法,可能是凌乱的代码,但它对我有用。我在IB中连接了一个标签和一个隐藏的文本字段,我使用UITextFieldDelegate委托编写了这段代码。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField == fineHiddenTextField) {
        NSString *fineText = [textField.text stringByReplacingCharactersInRange:range withString:string];
        if ([fineText length] == 0) {
            NSString *emptyFine = @"0.00";
            float fineValue = [emptyFine floatValue];
            fineEntryLabel.text = [NSString stringWithFormat:@"%.2f", fineValue];
        } else if ([fineText length] == 1) {
            NSString *firstDec = [NSString stringWithFormat:@"0.0%@", fineText];
            float fineValue = [firstDec floatValue];
            fineEntryLabel.text = [NSString stringWithFormat:@"%.2f", fineValue];
        } else if ([fineText length] == 2) {
            NSString *secondDec = [NSString stringWithFormat:@"0.%@", fineText];
            float fineValue = [secondDec floatValue];
            fineEntryLabel.text = [NSString stringWithFormat:@"%.2f", fineValue];
        } else {
            int decimalPlace = [fineText length] - 2;
            NSString *fineDollarAmt = [fineText substringToIndex:decimalPlace];
            NSString *fineCentsAmt = [fineText substringFromIndex:decimalPlace];
            NSString *finalFineValue = [NSString stringWithFormat:@"%@.%@", fineDollarAmt, fineCentsAmt];
            float fineValue = [finalFineValue floatValue];
            fineEntryLabel.text = [NSString stringWithFormat:@"%.2f", fineValue];
        }


        //fineEntryLabel.text = [NSString stringWithFormat:@"%.2f", fineValue];
        return YES;
    }
}

不完全是最好的,但它确实完成了工作。最初的if语句只是为了确保这只发生在这个特定的textField上(因为整个同一页面都有多个。)这段代码用于输入金钱(罚款金额)我想要它简单易用。只需将标签设置为从右侧对齐即可。

我现在对咖啡有点兴趣,但我会回答你的任何问题。 :)

答案 5 :(得分:0)

这是我的解决方案!

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    float valorUnit = [textField.text floatValue];

    if( string.length > 0)
    {
        float incremento = [string floatValue];

        valorUnit = valorUnit * 10.f + (incremento/100.f);
        NSString* strVal = [NSString stringWithFormat:@"%f", valorUnit];

        if (valorUnit > 0.f && valorUnit < 10.f) {
            textField.text  = [strVal substringToIndex:3];
        }
        else if (valorUnit < 100.f && valorUnit >= 10.f)
        {
            textField.text  = [strVal substringToIndex:4];
        }
        else if (valorUnit >=100.f && valorUnit <1000.f)
        {
            textField.text  = [strVal substringToIndex:5];
        }
        else {
            return NO;
        }

    }
    else {
        valorUnit = (valorUnit/10.f);
        NSString* strVal = [NSString stringWithFormat:@"%f", valorUnit];
        if (valorUnit > 0.f && valorUnit < 10.f) {
            textField.text  = [strVal substringToIndex:5];
        }
        else if (valorUnit < 100.f && valorUnit >= 10.f)
        {
            textField.text  = [strVal substringToIndex:6];
        }
        else if (valorUnit >=100.f && valorUnit <1000.f)
        {
            textField.text  = [strVal substringToIndex:7];
        }
        else {
            return NO;
        }
    }

return YES;

}

答案 6 :(得分:0)

我写了一个开源UITextField子类来处理这个问题,可以在这里找到:

https://github.com/TomSwift/TSCurrencyTextField

我采用的方法类似于Lars Schneider在其流行答案中的建议。但是我的版本完全封装在你可以在任何地方使用的可重用组件中,就像UITextField一样。如果您选择实现任何UITextFieldDelegate方法,但这不是必需的。