chrispalle
chrispalle

Reputation: 45

ObjC - Using NSRange, Allow User to Enter Only One decimal point -

building a simple calculator here to get my feet wet with iOS dev. I want to prohibit the entry of more than one decimal point. Put my logic in the comment.

It builds and runs with no problem, but it's not blocking the entry of more than one "." any help is appreciated. Thanks.

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];
    if (userIsInTheMiddleofTypingANumber) {
        [display setText:[[display text] stringByAppendingString:digit]];
        // if the user enters a decimal point, check if the existing display text contains a "." if not, then allow it, but if it does, do not allow it.
        NSString *decimal = @".";
        NSRange range = [digit rangeOfString:decimal];
            if (range.location == NSNotFound) {
                [display setText:digit];
            }

    } else {
        [display setText:digit];
        userIsInTheMiddleofTypingANumber = YES;
    }
}

Upvotes: 4

Views: 1945

Answers (5)

Chrys
Chrys

Reputation: 11

This worked for me:

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];

    if (userIsInTheMiddleOfTypingANumber)
    { 
        if (decimalEntered)
        {
            NSRange range = [digit rangeOfString:@"."];
            if (range.location == NSNotFound)
            {
                [display setText:[[display text] stringByAppendingString:digit]];
            }
            else
            {
                NSLog(@"You can't enter more than one decimal");
            }
        }
        else if (!decimalEntered)
        {
            NSRange range = [digit rangeOfString:@"."];
            if (range.location == NSNotFound)
            {
                [display setText:[[display text] stringByAppendingString:digit]];
            }
            else 
            {
                [display setText:[[display text] stringByAppendingString:digit]];
                decimalEntered = YES;
            }
        }
    }
    else 
    { 
        decimalEntered = NO;
        [display setText:digit];
        userIsInTheMiddleOfTypingANumber = YES; 
    }
}

Upvotes: 1

Jamie
Jamie

Reputation: 5112

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];
    NSString *decimal = @".";
    BOOL decimalAlreadyEntered = [display.text rangeOfString:decimal].location == NSNotFound ? NO : YES;

    if (userIsInTheMiddleofTypingANumber) {
        if (([digit isEqual:decimal] && !decimalAlreadyEntered) || !([digit isEqual:decimal])) {
            [display setText:[[display text] stringByAppendingString:digit]];
        }
    }
    else if (display.text isEqual:@"0" && digit == decimal){
         [display setText:[[display text] stringByAppendingString:digit]];
         userIsInTheMiddleofTypingANumber = YES;
    }
    else {
        [display setText:digit];
        userIsInTheMiddleofTypingANumber = YES;
    }
}

I think this should work. It looks like you are appending the digit first thing in your loop, even if a decimal has been entered. I haven't tried this code in the compiler but it checks to see if a decimal has been entered first.

Upvotes: 2

jscs
jscs

Reputation: 64002

Don't frustrate your user. Give them feedback about what you can and cannot accept for input:

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *char = [[sender titleLabel] text];
    if( [char isEqualTo:@"."] ){
        [sender setEnabled:NO];
    }

    [display setText:[[display text] stringByAppendingString:char]];
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)replacementRange replacementString:(NSString *)replacementString {
    // Re-enable the button if the decimal point is deleted
    NSRange rangeForPoint = [[display.text substringWithRange:replacementRange] 
                                   rangeOfString:@"."];
    if( NSNotFound != rangeForPoint.location ){
        // You may also want to check that replacementString does not contain a new
        // decimal point, in the case of pasted text, e.g.
        [decimalPointButton setEnabled:YES];
    }
}

This delegate method, textField:shouldChangeCharactersInRange:replacementString: is really the key to handling restricted input. You should also look at NSFormatter, which can take a format and validate input as the user types, using its isPartialStringValid... methods.

Upvotes: 2

Wolfgang Schreurs
Wolfgang Schreurs

Reputation: 11834

You might want to check an earlier post by me, which deals with sort of the same issue. I tried creating a textfield that accepts limited input (for example only numbers in the following format: 0.00). It never worked completely great (it had some bugs with currency I believe), but it might be good enough for your purposes:

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

Upvotes: 1

dks1725
dks1725

Reputation: 1631


Try below updated code of yours

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];
    if (userIsInTheMiddleofTypingANumber)  
    {
         // if the user enters a decimal point, check if the existing display text contains a "." if not, then allow it, but if it does, do not allow it.
         NSString *decimal = @".";
         NSRange range = [digit rangeOfString:decimal];
         if (range.location == NSNotFound)  
         {
             [display setText:[[display text] stringByAppendingString:digit]]; 
             [display setText:digit];
         }
    }
    else
    {
        [display setText:digit];
        userIsInTheMiddleofTypingANumber = YES;
    }
}

Upvotes: 0

Related Questions