ductran
ductran

Reputation: 10193

becomeFirstResponder not show keyboard in ios 11

I tried to show a keyboard on after loading screen like this:

 -(void) viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
     UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
     tf.borderStyle = UITextBorderStyleRoundedRect;
     tf.text = @"test";

    [self.view addSubview:tf]; 
    if([tf canBecomeFirstResponder]){
        [tf becomeFirstResponder]; // surely this line is called          
     }
 }

This code works on ios 8,9,10 but not 11. I'm not sure why the keyboard isn't show automatically on ios 11 while text field is focusing (has cursor). And in this case, keyboard's notification isn't called:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

- (void) keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = [note userInfo];
    CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    DLog(@"Keyboard Height: %f Width: %f", kbSize.height, kbSize.width);
 }

I even try this:

[tf performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0]; 

but still not work.

I have to click on text field to bring up the keyboard.
Is there anything update from Apple which I don't know?

Update: it looks like there is something wrong with my project or all my view controllers because I can't make the keyboard showing on all screens. But when I create new project with above code, it can work well. Here is one of the problem:

enter image description here

As you can see, I have to click on the textfield to show the keyboard, and from the second time, it can work properly. And this issue only happended on ios 11 (both simulator & device)
Here is the code for search field above:

    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 215, 30)];
    textField.backgroundColor = [UIColor clearColor];
    textField.placeholder = @"Enter text to search";
    textField.borderStyle = UITextBorderStyleLine;
    textField.layer.masksToBounds=YES;
    textField.layer.borderColor=[[UIColor lightGrayColor]CGColor];
    textField.layer.borderWidth= 1.0f;
    textField.returnKeyType = UIReturnKeySearch;
    textField.delegate = self;
    textField.clearButtonMode = UITextFieldViewModeAlways;
    [UIView transitionWithView:self.navigationController.navigationBar
                  duration:0.55f
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.navigationItem.titleView = textField;
                } completion:^(BOOL finished) {
                    [textField becomeFirstResponder];
                }];

I wonder is there anything cause conflict keyboard?

Upvotes: 5

Views: 4156

Answers (6)

trungduc
trungduc

Reputation: 12144

I have created a new project and tried your code. It works normally on both simulator and device iOS11. Keyboard is showed and notification is called. This is the code i have tried.

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(keyboardWillShow:)
                                               name:UIKeyboardWillShowNotification
                                             object:nil];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  UITextField* tf = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
  tf.borderStyle = UITextBorderStyleRoundedRect;
  tf.text = @"test";

  [self.view addSubview:tf];
  if ([tf canBecomeFirstResponder]) {
    [tf becomeFirstResponder];  // surely this line is called
  }
}

- (void)keyboardWillShow:(NSNotification*)note {
  NSDictionary* userInfo = [note userInfo];
  CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

  NSLog(@"Keyboard Height: %f Width: %f", kbSize.height, kbSize.width);
}

@end

You should check DLog method. I think keyboard's notification is called but nothing is logged because of DLog method.

Upvotes: 3

Borzh
Borzh

Reputation: 5195

When the TextField is not yet being drawn on the screen, then becomeFirstResponder() will not work. For example when it was hidden and never drawn. Then you need to call becomeFirstResponder() after it has been drawn. Maybe this will help:

DispatchQueue.main.async {
    tf.becomeFirstResponder()
}

Upvotes: 5

Timo
Timo

Reputation: 41

In my case the problem was, that I had 2 UIWindow objects and the one I used to add UI elements was not set as key window, and keyboard window had lower level, so keyboard was covered by my other window. I just had to call makeKeyAndVisible() on the second window. john07's comment helped me figure this out. For further reference check: https://developer.apple.com/library/archive/qa/qa1813/_index.html

Upvotes: 1

ductran
ductran

Reputation: 10193

It's really weird, because this issue can be fixed after showing a UIAlertView
So when I try to add a UIAlertView with loading indicator (and auto dimiss after few seconds) like this before showing keyboard with above code, it can work well.
Don't know the root cause of my project, but it works.
And it only happens on ios 11.

Upvotes: 0

ali ozkara
ali ozkara

Reputation: 5616

try this;

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
    [theTextField resignFirstResponder];
    return NO;
}

- (void)viewWillAppear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}


- (void)keyboardWillShow:(NSNotification *)notification {
        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
}

- (void)keyboardWillHide:(NSNotification *)notification {

}

Upvotes: 1

Martin
Martin

Reputation: 866

Try this one. I feel textField object is getting null in completion block and your calling becomeFirstResponder on that.

UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 215, 30)];
textField.backgroundColor = [UIColor clearColor];
textField.placeholder = @"Enter text to search";
textField.borderStyle = UITextBorderStyleLine;
textField.layer.masksToBounds=YES;
textField.layer.borderColor=[[UIColor lightGrayColor]CGColor];
textField.layer.borderWidth= 1.0f;
textField.returnKeyType = UIReturnKeySearch;
textField.delegate = self;
textField.clearButtonMode = UITextFieldViewModeAlways;
[UIView transitionWithView:self.navigationController.navigationBar
              duration:0.55f
               options:UIViewAnimationOptionTransitionCrossDissolve
            animations:^{
                self.navigationItem.titleView = textField;
            } completion:^(BOOL finished) {
                [((UITextField *)self.navigationItem.titleView) becomeFirstResponder];
            }];

Upvotes: 1

Related Questions