Re-Apply currency formatting to a UITextField on a change event

前端 未结 6 2125
日久生厌
日久生厌 2020-11-28 12:33

I\'m working with a UITextField that holds a localized currency value. I\'ve seen lots of posts on how to work with this, but my question is: how do I re-apply currency for

6条回答
  •  一生所求
    2020-11-28 12:48

    I've been working on this issue and I think I figured out a nice, clean solution. I'll show you how to appropriately update the textfield on user input, but you'll have to figure out the localization yourself, that part should be easy enough anyway.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
    
        // setup text field ...
    
    #define PADDING 10.0f
    
        const CGRect bounds = self.view.bounds;
        CGFloat width       = bounds.size.width - (PADDING * 2);
        CGFloat height      = 30.0f;
        CGRect frame        = CGRectMake(PADDING, PADDING, width, height);
    
        self.textField                      = [[UITextField alloc] initWithFrame:frame];
        _textField.backgroundColor          = [UIColor whiteColor];
        _textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
        _textField.autocapitalizationType   = UITextAutocapitalizationTypeNone;
        _textField.autocorrectionType       = UITextAutocorrectionTypeNo;
        _textField.text                     = @"0";
        _textField.delegate                 = self;
        [self.view addSubview:_textField];
    }
    
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    
    
        // force update for text field, so the initial '0' will be formatted as currency ...
    
        [self textField:_textField shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@"0"];
    }
    
    - (void)viewDidUnload
    {
        self.textField = nil;
    
        [super viewDidUnload];
    }
    

    This is the code in the UITextFieldDelegate method textField:shouldChangeCharactersInRange:replacementString:

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        NSString *text             = _textField.text;
        NSString *decimalSeperator = @".";
        NSCharacterSet *charSet    = nil;
        NSString *numberChars      = @"0123456789";
    
    
        // the number formatter will only be instantiated once ...
    
        static NSNumberFormatter *numberFormatter;
        if (!numberFormatter)
        {
            numberFormatter = [[NSNumberFormatter alloc] init];
            numberFormatter.numberStyle           = NSNumberFormatterCurrencyStyle;
            numberFormatter.maximumFractionDigits = 10;
            numberFormatter.minimumFractionDigits = 0;
            numberFormatter.decimalSeparator      = decimalSeperator;
            numberFormatter.usesGroupingSeparator = NO;
        }
    
    
        // create a character set of valid chars (numbers and optionally a decimal sign) ...
    
        NSRange decimalRange = [text rangeOfString:decimalSeperator];
        BOOL isDecimalNumber = (decimalRange.location != NSNotFound);
        if (isDecimalNumber)
        {
            charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];        
        }
        else
        {
            numberChars = [numberChars stringByAppendingString:decimalSeperator];
            charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];
        }
    
    
        // remove amy characters from the string that are not a number or decimal sign ...
    
        NSCharacterSet *invertedCharSet = [charSet invertedSet];
        NSString *trimmedString = [string stringByTrimmingCharactersInSet:invertedCharSet];
        text = [text stringByReplacingCharactersInRange:range withString:trimmedString];
    
    
        // whenever a decimalSeperator is entered, we'll just update the textField.
        // whenever other chars are entered, we'll calculate the new number and update the textField accordingly.
    
        if ([string isEqualToString:decimalSeperator] == YES) 
        {
            textField.text = text;
        }
        else 
        {
            NSNumber *number = [numberFormatter numberFromString:text];
            if (number == nil) 
            {
                number = [NSNumber numberWithInt:0];   
            }
            textField.text = isDecimalNumber ? text : [numberFormatter stringFromNumber:number];
        }
    
        return NO; // we return NO because we have manually edited the textField contents.
    }
    

    Edit 1: fixed memory leak.

    Edit 2: updated for Umka - handling of 0 after decimal separator. Code is updated for ARC as well.

提交回复
热议问题