Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to format a UITextField to behave like a currency calculator for only numeric input in iOS

I have a UITextField in my application that is supposed to receive only numeric input from the user. This numeric input is supposed to represent currency (i.e. have only two decimal places), have the default value of 0.00 when nothing has been entered. I also would like to have a "$" sign that is on the far left, with the number right aligned, such that the number moves from right to left like such:

e.g. when entering the number "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. and so on...

I have the UITextField right aligned so that it already moves the numbers over to the left from the right. However, I need to place the "$" inside the UITextField, and I would like the default 0.00 value to be modified to the number entered by the user one digit at a time. The user should NOT have to enter the decimal point, as it should already be in the textfield holding its position. I then would like the number to have a "," to be automatically entered to separate every three digits. I would like the application to do this AS THE USER IS ENTERING THE NUMBERS, and not formatted afterwards when everything is entered. How would I do this? I have seen a lot of people say that I am to use NSNumberFormatter, but I want to know how do I use it in conjunction with the UITextField such that it formats the numeric text on the fly, as described above?

I have found the following question posted on StackOverflow some time ago:

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

but I want to know how to actually incorporate it as a solution to my problem.

like image 887
syedfa Avatar asked Mar 05 '13 06:03

syedfa


4 Answers

Here's a nice way to do it. Remember to set your UITextField to self in the viewDidLoad method and your header file must conform to the UITextFieldDelegate protocol

-(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;
}
like image 191
Daniel Avatar answered Nov 15 '22 21:11

Daniel


Updated Answer for 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
    }
like image 21
Priyatham51 Avatar answered Nov 15 '22 23:11

Priyatham51


Here is my solution in Swift. My approach was keeping track of the numbers entered and multiplying it by 0.01 and setting the result number with 2 decimal points using NSNumberFormatter. Note that I have the textfield keyboard set as the number pad.

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
}
like image 35
julien Avatar answered Nov 15 '22 21:11

julien


You likely need to check out the UITextFieldDelegate protocol. By assigning something (most commonly your ViewController class) as the UITextField's delegate, you'll be able to receive interactive text entry events from the control. In particular:

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

By returning NO from that method, you can prevent the text field from applying the keys pressed by the user.

However, even though you return NO there's nothing to prevent you from using the information passed to the delegate method to do your own manipulation of the text field contents in code.

In pseudo-code form:

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

Disclaimer: I haven't written actual code to test, so it's possible that altering the code inside this delegate method causes another shouldChangeCharactersInRange: message to fire. I don't believe that's the case, though. I don't believe the delegate event fires when you alter the text in code.

This obviously isn't as good as a custom control that already implements all the rules for a number text entry box (I'm having flashbacks to years of Visual Basic programming now...). But I don't know of any such control that someone's written and open-sourced.

like image 44
Bill Patterson Avatar answered Nov 15 '22 22:11

Bill Patterson