How do I scroll the UIScrollView when the keyboard appears? How do I scroll the UIScrollView when the keyboard appears? ios ios

How do I scroll the UIScrollView when the keyboard appears?


The recommended way from Apple is to change the contentInset of the UIScrollView. It is a very elegant solution, because you do not have to mess with the contentSize. Following code is copied from the Keyboard Programming Guide, where the handling of this issue is explained. You should have a look into it.

// Call this method somewhere in your view controller setup code.- (void)registerForKeyboardNotifications{    [[NSNotificationCenter defaultCenter] addObserver:self            selector:@selector(keyboardWasShown:)            name:UIKeyboardDidShowNotification object:nil];   [[NSNotificationCenter defaultCenter] addObserver:self             selector:@selector(keyboardWillBeHidden:)             name:UIKeyboardWillHideNotification object:nil];}// Called when the UIKeyboardDidShowNotification is sent.- (void)keyboardWasShown:(NSNotification*)aNotification{    NSDictionary* info = [aNotification userInfo];    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);    scrollView.contentInset = contentInsets;    scrollView.scrollIndicatorInsets = contentInsets;    // If active text field is hidden by keyboard, scroll it so it's visible    // Your application might not need or want this behavior.    CGRect aRect = self.view.frame;    aRect.size.height -= kbSize.height;    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height);        [scrollView setContentOffset:scrollPoint animated:YES];    }}// Called when the UIKeyboardWillHideNotification is sent    - (void)keyboardWillBeHidden:(NSNotification*)aNotification{    UIEdgeInsets contentInsets = UIEdgeInsetsZero;    scrollView.contentInset = contentInsets;    scrollView.scrollIndicatorInsets = contentInsets;}

Swift version:

func registerForKeyboardNotifications() {    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)}// Don't forget to unregister when donedeinit {    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidHide, object: nil)}@objc func onKeyboardAppear(_ notification: NSNotification) {    let info = notification.userInfo!    let rect: CGRect = info[UIKeyboardFrameBeginUserInfoKey] as! CGRect    let kbSize = rect.size    let insets = UIEdgeInsetsMake(0, 0, kbSize.height, 0)    scrollView.contentInset = insets    scrollView.scrollIndicatorInsets = insets    // If active text field is hidden by keyboard, scroll it so it's visible    // Your application might not need or want this behavior.    var aRect = self.view.frame;    aRect.size.height -= kbSize.height;    let activeField: UITextField? = [addressTextView, servicePathTextView, usernameTextView, passwordTextView].first { $0.isFirstResponder }    if let activeField = activeField {        if !aRect.contains(activeField.frame.origin) {            let scrollPoint = CGPoint(x: 0, y: activeField.frame.origin.y-kbSize.height)            scrollView.setContentOffset(scrollPoint, animated: true)        }    }}@objc func onKeyboardDisappear(_ notification: NSNotification) {    scrollView.contentInset = UIEdgeInsets.zero    scrollView.scrollIndicatorInsets = UIEdgeInsets.zero}


I just implemented this with Swift 2.0 for iOS9 on Xcode 7 (beta 6), works fine here.

override func viewWillAppear(animated: Bool) {    super.viewWillAppear(animated)    registerKeyboardNotifications()}func registerKeyboardNotifications() {    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)}deinit {    NSNotificationCenter.defaultCenter().removeObserver(self)}func keyboardWillShow(notification: NSNotification) {    let userInfo: NSDictionary = notification.userInfo!    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size    let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)    scrollView.contentInset = contentInsets    scrollView.scrollIndicatorInsets = contentInsets    var viewRect = view.frame    viewRect.size.height -= keyboardSize.height    if CGRectContainsPoint(viewRect, textField.frame.origin) {        let scrollPoint = CGPointMake(0, textField.frame.origin.y - keyboardSize.height)        scrollView.setContentOffset(scrollPoint, animated: true)    }}func keyboardWillHide(notification: NSNotification) {    scrollView.contentInset = UIEdgeInsetsZero    scrollView.scrollIndicatorInsets = UIEdgeInsetsZero}

Edited for Swift 3

Seems like you only need to set the contentInset and scrollIndicatorInset with Swift 3, the scrolling/contentOffset is done automatically..

override func viewWillAppear(_ animated: Bool) {    super.viewWillAppear(animated)    registerKeyboardNotifications()}func registerKeyboardNotifications() {    NotificationCenter.default.addObserver(self,                                         selector: #selector(keyboardWillShow(notification:)),                                         name: NSNotification.Name.UIKeyboardWillShow,                                         object: nil)    NotificationCenter.default.addObserver(self,                                         selector: #selector(keyboardWillHide(notification:)),                                         name: NSNotification.Name.UIKeyboardWillHide,                                         object: nil)}deinit {    NotificationCenter.default.removeObserver(self)}func keyboardWillShow(notification: NSNotification) {    let userInfo: NSDictionary = notification.userInfo! as NSDictionary    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue    let keyboardSize = keyboardInfo.cgRectValue.size    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)    scrollView.contentInset = contentInsets    scrollView.scrollIndicatorInsets = contentInsets}func keyboardWillHide(notification: NSNotification) {    scrollView.contentInset = .zero    scrollView.scrollIndicatorInsets = .zero}


Swift 5 Solution:

override func viewWillAppear(_ animated: Bool) {    super.viewWillAppear(animated)    registerKeyboardNotifications()}func registerKeyboardNotifications() {    NotificationCenter.default.addObserver(self,                                         selector: #selector(keyboardWillShow(notification:)),                                         name: UIResponder.keyboardWillShowNotification,                                         object: nil)    NotificationCenter.default.addObserver(self,                                         selector: #selector(keyboardWillHide(notification:)),                                         name: UIResponder.keyboardWillHideNotification,                                         object: nil)}override func viewWillDisappear(_ animated: Bool) {    super.viewWillDisappear(animated)    NotificationCenter.default.removeObserver(self)}@objc func keyboardWillShow(notification: NSNotification) {    let userInfo: NSDictionary = notification.userInfo! as NSDictionary    let keyboardInfo = userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue    let keyboardSize = keyboardInfo.cgRectValue.size    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)    scrollView.contentInset = contentInsets    scrollView.scrollIndicatorInsets = contentInsets}@objc func keyboardWillHide(notification: NSNotification) {    scrollView.contentInset = .zero    scrollView.scrollIndicatorInsets = .zero}