Grady Player
Grady Player

Reputation: 14549

What is the correct way to change keyboard return button for UITextView

So I have been working on a small requirement that has taken me way more time than I would like, as small requirements in UIKit seem to do sometimes:

When a user enters a password longer than 3 characters you change the keyboard to have a done button.

Simple enough... it seems that KVO isn't fired until editing ends, and neither is the textFieldDidEndEditing: delegate method called. Ok, easy enough, just do our logic in the
-(BOOL)textField:shouldChangeCharactersInRange:replacementString: delegate callback...

Attempt A:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if (newString.length >=3)
    {
        textField.returnKeyType = UIReturnKeyGo;
    }
    return YES;
}

Attempt A, does nothing... never changes the keyboard to Go

Attempt B:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if (newString.length >=3)
    {
        textField.returnKeyType = UIReturnKeyGo;
        [textField resignFirstResponder];
        [textField becomeFirstResponder];
    }
    return YES;
}

Attempt B: yay, keyboard button changes, but when we resignFirstResponder, we discard the new input so the User can't enter their password... bad

Attempt C:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if (newString.length >=3)
    {
        textField.returnKeyType = UIReturnKeyGo;
    }else{
        textField.returnKeyType = UIReturnKeyDefault;
    }
    textField.text = newString;
    [textField resignFirstResponder];
    [textField becomeFirstResponder];

    return NO;
}

Attempt C is tricky, we return NO, telling the delegate not to accept the edit, but that is ok, because we explicitly set the string in the delegate (this seems like sort of a bad idea), but it all works, except that when you resign firstResponder status it changes your keyboard (if you had the number keyboard up, it will switch to default after every keystroke)

Attempt D:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString * newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if (newString.length >=3)
    {
        textField.returnKeyType = UIReturnKeyGo;
    }else{
        textField.returnKeyType = UIReturnKeyDefault;
    }
    //detect if we have crossed a boundry
    if ((textField.text.length >=3) != (newString.length >=3))
    {
        [textField resignFirstResponder];
        [textField becomeFirstResponder];
    }
    textField.text = newString;

    return NO;
}

Attempt D is pretty good, it will only resign first responder as you cross the 2/3 or 3/2 edge so you only lose your keyboard once, not a big deal usually

so the question, what is the best practice way to do this? (resigning first responder only seems to cancel the edit if using secure input, if you aren't familiar with this problem), I have also prepared a sample project, as to help anyone that wants to look at it: sample project

Upvotes: 0

Views: 556

Answers (3)

DURGESH
DURGESH

Reputation: 2453

Try this textField.returnKeyType = UIReturnKeyNext;

Upvotes: 0

w0mbat
w0mbat

Reputation: 2459

That's far too much work. Just make yourself the delegate of the UITextView and you will get TextViewDidChange messages.

- (void)textViewDidChange:(UITextView *)textView;

Or if using a UITextField register for its UITextFieldTextDidChangeNotification message.

Upvotes: 1

Coldsteel48
Coldsteel48

Reputation: 3512

add the delegate on text did change

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];  


-(void)textFieldDidChange :(UITextField *)theTextField 
{
   enter your logic here 
}

Upvotes: 0

Related Questions