How to make UITextField move up when keyboard is present

Share the joy
  •  
  •  
  •  
  •  

When the user taps in a text field, that text field becomes the first responder and automatically asks the system to display the associated keyboard. The appearance of the keyboard might obscure portions of the UI that you would like to keep visible. Usually the content scrolls up so that it doesn’t get obscured by the keyboard. Let’s find out how to do that.

I’ll use as example a simple sign in view with two UITextFields, one for username and one for password and a sign in button.

sign_in_no_keyboard

 

When we tap on one of those text fields the keyboard appears and it will obscure the sign in button and the password text field:

sign_in_keyboard_present

 

It would be nice if the text fields would move up so that they are in the centre of the screen and the sign in button is visible underneath. To do this we will use a UIScrollView and make sure we scroll the content so it’s positioned in the centre of the screen. If you have your text fields in a nib file or storyboard then all you need to do is embed it in a scroll view. For our sign in view I will select all the controls I want to scroll (this includes labels, the two text fields and the sign in button) and go to Editor -> Embed In -> Scroll View. If you have created the text field programatically then create a UIScrollView and add the text field to it.

We need to sign up to receive notifications for when the keyboard appears and disappears. We will create a method called registerForKeyboardNotifications and one deregisterForKeyboardNotifications. We will call registerForKeyboardNotifications from viewWillAppear: and deregisterFromKeyboardNotifications in viewWillDisappear:

- (void)registerForKeyboardNotifications {

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];

}

- (void)deregisterFromKeyboardNotifications {

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardDidHideNotification
                                                  object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];

}

- (void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    [self registerForKeyboardNotifications];

}

- (void)viewWillDisappear:(BOOL)animated {

    [self deregisterFromKeyboardNotifications];

    [super viewWillDisappear:animated];

}

We want to scroll the content so that the sign in button is above the keyboard. To do this we get the current location of the sign in button, check if it’s being obscured by the keyboard and if it is then we scroll the content up so that the button is visible just above the keyboard. Here is the code for this:

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

    NSDictionary* info = [notification userInfo];

    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGPoint buttonOrigin = self.signInButton.frame.origin;

    CGFloat buttonHeight = self.signInButton.frame.size.height;

    CGRect visibleRect = self.view.frame;

    visibleRect.size.height -= keyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, buttonOrigin)){

        CGPoint scrollPoint = CGPointMake(0.0, buttonOrigin.y - visibleRect.size.height + buttonHeight);

        [self.scrollView setContentOffset:scrollPoint animated:YES];

    }

}

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

    [self.scrollView setContentOffset:CGPointZero animated:YES];

}

So, to summarise, these are the steps we took:

  1. Embed the UI controls in a UIScrollView
  2. Register for keyboard notifications
  3. Scroll the scroll view so that the content you want visible is above the keyboard


Share the joy
  •  
  •  
  •  
  •  

12 thoughts on “How to make UITextField move up when keyboard is present

    • That’s because the code is using UIKeyboardDidShowNotification, which makes animation after the keyboard is shown.
      Instead, the code should use UIKeyboardWillShowNotification.

  1. Works well! Thanks for sharing! By the way, I was working in landscape orientation, so I had to use the frame and keyboard widths instead of the height. 🙂

  2. Great post! Issue however, the “self.scrollview” is giving me and error. “Property of ‘scrollView’ not found on object of type ‘ViewController,’ it reads.

  3. Unfortunately this works only if you have only one UITextField under the fold. What if you have 10 fields?

    Then this “signInButton” has to be something else:
    CGPoint buttonOrigin = self.signInButton.frame.origin;

  4. This, like all examples of its kind, assumes that the scrollview has an origin of 0,0 – if your scrollview doesn’t you’ll need to add on the y position from _scrollview.frame.origin.y to buttonOrigin.y

    It would also be worth tracking in textFieldDidBeginEditing/EndEditing which textField has become active and take the calculations from that, rather than hard-coding to a particular view.

    • This is important info. Even the example of Apple’s site does not seem to account for the fact that the scroll view may not be at 0,0. I wonder if the best practice should be to always add a scroll view at the 0,0 and use it for keyboard management instead of taking the scroll view’s height into account inside the keyboard notification handlers.

Leave a Reply

Your email address will not be published. Required fields are marked *

*