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
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • Have you tried placing that code in `viewWillAppear`? – Yuliani Noriega Nov 20 '12 at 18:54
  • @yulz Yes, my original code was in `-viewWillAppear:`. – Jeffery Thomas Nov 21 '12 at 00:05
  • 1
    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. – Anton Dec 11 '12 at 07:44
  • 1
    @Anton 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]` – Jeffery Thomas Dec 11 '12 at 14:04
  • 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)]`; – Anton Dec 11 '12 at 14:31
  • 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. – Anton Dec 11 '12 at 14:33
  • @Anton 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. – Jeffery Thomas Dec 11 '12 at 16:12
  • @JefferyThomas That's actually really interesting, I had no idea. Great things you learn on SO! – Anton Dec 11 '12 at 16:18
  • As old as this is, I think it's a dupe of the even older (and fully solved) http://stackoverflow.com/questions/2658261/uitextfield-subview-of-uitableviewcell-to-become-first-responder – Steven Fisher Feb 05 '14 at 21:40
  • @StevenFisher It seems like quite a different, way less elegant, solution than working with the runloop IMO. – SmileBot Mar 04 '15 at 20:15
  • Where's the runloop? – Steven Fisher Mar 05 '15 at 20:52
  • 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. :) – Steven Fisher Mar 05 '15 at 20:54

4 Answers4

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.

k20
  • 2,008
  • 1
  • 17
  • 23
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?

agierens
  • 132
  • 9
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 ;)

stm
  • 121
  • 1
  • 6
-4

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

Bernat
  • 1,537
  • 3
  • 18
  • 40