Struggling with currency in Cocoa

不羁岁月 提交于 2019-11-29 00:14:36

My solution:


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

Here's the rough plan of attack I'd use if I had to write that now. The trick will be typing into a hidden UITextField and updating a UILabel with the formatted value as the user types.

  1. Create a UITextField, make it hidden, assign it a delegate, and then make it the first responder to summon the keyboard.
  2. In your delegate, respond to the textDidChange: message (too lazy to look up the exact name) by taking the text field's new value and converting it to a number. Make sure empty string converts to zero.
  3. Run the number through your formatter, and update a UILabel with that formatted currency value.

On every key press, the label will be updated, so the user will feel as though she is editing the formatted value, when she is really editing the hidden text field. How sneaky!

Well, i think this is better:

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

Try it out :)

Since I am lazy, and I can't stand having my input reformatted "to help me out" on the fly, I say:

Just let them enter a decimal number. When they leave the field, reformat it.

Well, this is a bit late but I figured I would give this a shot anyway. This is probably more of a workaround and may be messy code, but it worked for me. I connected a label and a hidden textfield in IB, and I wrote this code using the UITextFieldDelegate delegate.

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

Not exactly the neatest, but it really got the job done. The initial if statement was just to make sure that this was only happening for this one particular textField (As there are multiple throughout the same page.) This code was intended for the input of money (The amount of a fine paid) and I wanted it to be simple and easy to use. Just set your label to align from the right, and it should.

I am a little wired on coffee right now, but I will answer any questions you may have. :)

Here's my solution!

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

}

I wrote an open source UITextField subclass to handle this, available here:

https://github.com/TomSwift/TSCurrencyTextField

The approach I took is similar to what Lars Schneider suggests in his popular answer. But my version is fully encapsulated in a reusable component that you use anywhere, just like UITextField. If you choose to implement any UITextFieldDelegate methods you can, but this is not required.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!