In iOS 6, -[UITextField becomeFirstResponder] doesn't work in -viewWillAppear:
Asked Answered
A

4

17

In iOS 5.1 and iOS 5.0 it works, but in iOS 6.0 the keyboard does not show.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    UITextField *textField = self.emailAddressTextField;
    [textField becomeFirstResponder];
}

For now I moved the logic to -viewDidAppear:.

// This works but is not desirable.
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    UITextField *textField = self.emailAddressTextField;
    [textField becomeFirstResponder];
}

This works, but is not desirable. The keyboard slide-up animation is shown after the view loads.

I want to keyboard to be present as the slide-to-left animation presents the view being loaded in the navigation controller.

Do anyone know how to have the keyboard loaded as the view appears in iOS 6?

update

Based on @Duck's feedback, I did a little more testing. This seems to be specific to UITextFields contained in UITableViewCells.

Does anyone have any suggestions?

FIRST SOLUTION

So a full description. This is a table view with two static cell (email and password). There is a login button in a view that is assigned the table footer view. The two cells have have a text field in them and are of a custom type SICOTextFieldCell.

My solution was to put a fake text field behind the login button (in the table footer view).

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    UITextField *textField = self.SICO_fakeTextField;
    [textField becomeFirstResponder];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    UITextField *textField = self.SICO_emailAddressTextField;
    [textField becomeFirstResponder];
}

NEW SOLUTION

Based on the answer by @stm, I came up with a new (superior?) solution.

My solution was to call -selectRowAtIndexPath:animated:scrollPosition:. -[SICOTextFieldCell setSelected:animated:], which is a custom table view cell, calls [self.textField becomeFirstResponder] which magically draws the keyboard correctly. It's still a hack, but it's a cleaner hack.

@interface SICOLogInViewController ()
@property (readonly, nonatomic) UITextField *SICO_emailAddressTextField;
@property (readonly, nonatomic) UITextField *SICO_passwordTextField;
@end

@implementation SICOLogInViewController

- (IBAction)logIn
{
    // Controller Details
}

#pragma mark Private

- (UITextField *)SICO_textFieldForRowAtIndexPath:(NSIndexPath *)indexPath
{
    SICOTextFieldCell *cell = (SICOTextFieldCell *)[self.tableView cellForRowAtIndexPath:indexPath];
    return cell.textField;
}

#pragma mark View lifecycle

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
                                animated:NO scrollPosition:UITableViewScrollPositionTop];
}

#pragma mark UITextFieldDelegate

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    switch (textField.returnKeyType) {
        case UIReturnKeyGo:   [self logIn];                                       break;
        case UIReturnKeyNext: [self.SICO_passwordTextField becomeFirstResponder]; break;
        default: break;
    }
    return YES;
}

#pragma mark Properties

- (UITextField *)SICO_emailAddressTextField
{
    return [self SICO_textFieldForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}

- (UITextField *)SICO_passwordTextField
{
    return [self SICO_textFieldForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
}

@end
Angelicangelica answered 20/11, 2012 at 18:46 Comment(12)
Have you tried placing that code in viewWillAppear?Arvonio
@yulz Yes, my original code was in -viewWillAppear:.Angelicangelica
There's something else in your code throwing it off, this should run fine. If you want a quick fix, call [textField performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.1f]; instead of [textField becomeFirstResponder];. This will set the first responder 1/10 of a second later, presumably giving whatever problematic code you might have time to finish running and not stop it 1/10 of a second later. This is a sloppy workaround, though, not the ideal solution.Zsa
@Zsa First, I want to say this works. The problem is the effect is very odd. The view slides in from the right followed by the keyboard sliding in from the right 1/2 second later. This is better than the view sliding in from the right followed by the keyboard sliding up from the bottom 1/2 second later. I used a delay of 0. [textField performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.0f]Angelicangelica
Glad to hear that at least the workaround works. By the way, if you're going to have a delay of 0, you can just call [textField performSelector:@selector(becomeFirstResponder)];Zsa
I'm not sure what causes the weird sliding effects for you without seeing you full code. Consider posting your full code so we can get you a good solution.Zsa
@Zsa I don't believe -performSelector:withObject:afterDelay: with a delay of 0 is the same as -performSelector:. -performSelector: passes the message right away, while -performSelector:withObject:afterDelay: with a delay of 0 schedules the message to be passed in the next run loop.Angelicangelica
@JefferyThomas That's actually really interesting, I had no idea. Great things you learn on SO!Zsa
As old as this is, I think it's a dupe of the even older (and fully solved) #2658761Jagannath
@StevenFisher It seems like quite a different, way less elegant, solution than working with the runloop IMO.Natalianatalie
Where's the runloop?Jagannath
Oh! I totally misread that. You want to manipulate the runloop, rather than creating a temporary field. Sure, if you like that. It seems horrible to me, though. :)Jagannath
G
5

Try calling it in the cellForRowAtIndexPath method after creating the cell, or in the viewWillAppear of the tableViewCell that contains that textField.

If that gives you the same result and you still want the keyboard to appear before, I would use a "fake" textField to display the keyboard in the beginning. My guess is that your textField hasn't been added before the viewWillAppear.

Gladine answered 6/12, 2012 at 20:30 Comment(2)
I second the "fake" textfield solution.Philae
I think "fake" textField is the winner! Thanks k20. I'll post my solution in a minute.Angelicangelica
L
2

I tried your code exactly, iOS6 & in viewWillAppear and it seemed to work fine. Your trying to have the keyboard already displayed when you push over to a different view am i correct?

Lavery answered 25/11, 2012 at 12:6 Comment(1)
I'm sorry, but that doesn't really help. It points out that this issue is not universal, so I'll update my question.Angelicangelica
A
2

I'm currently writing my own Input Form Kit and struggled a few hours with this problem. After finding out, that my coding was fine, I found this question pointing to a possible glitch in iOS 6 and worked on a solution for this.

If you have (or create) a custom UITableViewCell, an easy solution would be to just subclass - (void) layoutSubviews; and check if the cell's UITextField should be the first responder (i.e. by checking if the text field is the same as the focused field set in your delegate). If so, just call - (BOOL) becomeFirstResponder; on your UITextField (again).

This is definitely a better solution than creating a "fake" UITextField ;)

Alisealisen answered 2/1, 2013 at 10:24 Comment(0)
S
-4

-viewWillAppear is maybe not called in iOS6? Have you tried to put your code in - (void)viewWillLayoutSubviews?

Sidnee answered 11/12, 2012 at 7:38 Comment(1)
I can verify that -viewWillAppear: is being called.Angelicangelica

© 2022 - 2024 — McMap. All rights reserved.