Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing returnButton while editing freezes keyboard for 1 tap

I'm making a login screen for my app and i want the return button to say "Next" when there is a field that is not yet filled out and it sould say "Go" when all fields are filled (i'm talking about UITextFields).

The code below works fine in that it shows Next and Go at the correct moments. But whenever it changes from "Next" to "Go" the next tap on the keyboard is ignored. When it says "Go" and i empty the textfield by backspacing there is no such problem and it shows Next as it should. It's almost like the old keyboard is still there and vanishes after being tapped.

My question is: what is the source of this problem and more importantly how do i get rid of this freezing up of the keyboard?

UITextField *theSender = (UITextField *)sender;
if (allTextFieldsAreFilled) {
    if (theSender.returnKeyType!=UIReturnKeyGo) {
        theSender.returnKeyType = UIReturnKeyGo;
        [theSender resignFirstResponder];
        [theSender becomeFirstResponder];
    }
} else {
    if (theSender.returnKeyType!=UIReturnKeyNext) {
        theSender.returnKeyType = UIReturnKeyNext;
        [theSender resignFirstResponder];
        [theSender becomeFirstResponder];
    }
}

This code gets called every time the value of one of the three UITextFields is changed, so it is an IBAction connected to the Editing Changed event.

Thanks in advance for your help!

EDIT

I found out this will only occur if the textfield is set to secure (password). When it is not set to secure it will not freeze up and my code works perfectly! The problem is that the change to the "Go" button will generally occur when a 'secure' textfield is fist responder. So this doesn't change anything to the problem.

like image 820
Manuel Avatar asked Nov 14 '22 05:11

Manuel


1 Answers

I created a new Single View Application project to test this out; and dropped the following code in the ViewController.m

#import "ViewController.h"

@interface ViewController () <UITextFieldDelegate>
{
    @private
    IBOutlet UITextField* m_fieldA;
    IBOutlet UITextField* m_fieldB;
    IBOutlet UITextField* m_fieldC;
}

@end

@implementation ViewController

// connected to Editing Did Begin
- (IBAction) onFocus:(UITextField*)_textField
{
    [self updateKeyboardFor:_textField];
}

// connected to Editing Changed
- (IBAction) onChanged:(UITextField*)_textField
{
    [self updateKeyboardFor:_textField];
}

- (void) updateKeyboardFor:(UITextField*)_textField
{
    bool allTextFieldsAreFilled = [m_fieldA.text length] && [m_fieldB.text length] && [m_fieldC.text length];

    if (allTextFieldsAreFilled)
    {
        if (_textField.returnKeyType != UIReturnKeyGo)
        {
            _textField.returnKeyType = UIReturnKeyGo;
            //[_textField resignFirstResponder];
            //[_textField becomeFirstResponder];
            [_textField reloadInputViews];
        }
    }
    else
    {
        if (_textField.returnKeyType != UIReturnKeyNext)
        {
            _textField.returnKeyType = UIReturnKeyNext;
            //[_textField resignFirstResponder];
            //[_textField becomeFirstResponder];
            [_textField reloadInputViews];
        }
    }
}

// A part of UITextFieldDelegate
- (BOOL) textFieldShouldReturn:(UITextField*)_textField
{
    if (_textField.returnKeyType == UIReturnKeyGo)
    {
        [_textField resignFirstResponder];

        // go off and perform 'go'
    }
    else
    {
        if(_textField == m_fieldA) [m_fieldB becomeFirstResponder];
        if(_textField == m_fieldB) [m_fieldC becomeFirstResponder];
        if(_textField == m_fieldC) [m_fieldA becomeFirstResponder];
    }

    return true;
}

@end

Then in the XIB create three UITextFields and hooked them up to the IBOutlets, IBActions, and also set this view controller as the delegate for all the fields.

All seems to work fine regardless of secure fields.

My guess is that your issue is somewhere in the code where you move to the 'Next' field; and not in the code that you posted. Also make sure that all your outlets and delegates are linked up properly.


Update: I've edited the code above. The commented out lines were the problem, you should be using reloadInputViews to update the button.

It seems that it wasn't locking the keyboard; but what it was doing was after you typed the first letter and did the resign/become calls to refresh the button then the second press would overwrite the first. This seems like a bug in iOS... it's more noticeable if after the first letter you type a space. When I noticed that I added a label that updated it's content with the contents of the password field and it was even more clear what was happening.

like image 61
Wex Avatar answered Jan 04 '23 07:01

Wex