Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView contentInset not updating when keyboard interactively dismissed

Update

I found that in my many refactorings I was inheriting from UIViewController instead of UITableViewController, so I was missing some automatic behaviours that UITableViewController provides. However, I still needed to manually handle the scroll views insets when the keyboard was being interactively dismissed. See my updated answer.


I am trying to emulate iMessage in how the keyboard is dismissed when the user drags it to the bottom of the screen. I have it working with one small visual issue that's bugging me.

As the keyboard is dragged off the screen the scroll indicators do not resize correctly - that is until it has been completely dismissed.

I use keyboard notifications to tell me when the keyboard has appeared to increase the content and scroll insets by the height of the keyboard. It seems I didn't need to do anything when the keyboard has been dismissed as the insets appear to be correct when it has been. However when dismissing interactively I can't update the insets during the dragging event.

To illustrate the issue, the first image shows that content has scrolled off the top of the screen due to the space being occupied by the keyboard; the user has scrolled to the last row in the table:

Keyboard displayed, content scrolled to bottom

Here, the keyboard is being dismissed and is almost completely off-screen. However notice how the scroll indicators are completely the wrong size. All of the content is now almost on screen so the indicators should be stretching, however, what happens is that as the keyboard moves down, the scroll indicators move up and do not stretch. This is not what happens in iMessage.

Keyboard being dismissed

I think what I'm doing is pretty standard, I'm creating a UIToolBar (iOS 8.3) and overriding these methods in my view controller:

override var inputAccessoryView: UIView {
    return toolbar
}

override func canBecomeFirstResponder() -> Bool {
    return true
}

func willShowKeyboard(notification: NSNotification) {
    let keyboardFrame = notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
    tableView.contentInset.bottom = keyboardFrame.CGRectValue().height
    tableView.scrollIndicatorInsets.bottom = keyboardFrame.CGRectValue().height
}
like image 946
Paul Avatar asked Apr 11 '15 23:04

Paul


1 Answers

Update

After switching to a UITableViewController, I found that this implementation of scrollViewDidScroll() (along with the other methods in the original solution below) did the trick of dynamically resizing the insets when the keyboard was interactively dismissed.

override func scrollViewDidScroll(scrollView: UIScrollView) {

    if !keyboardShowing {
        return
    }

    let toolbarFrame = toolbar.convertRect(toolbar.frame, toView: nil)

    tableView.scrollIndicatorInsets.bottom = view.bounds.height - toolbarFrame.minY
    tableView.contentInset.bottom = view.bounds.height - toolbarFrame.minY
}

I've managed to achieve the same effect. I'm not sure if this is the correct method, but it works nicely. I'll be interested to know what other solutions there might be.

func didShowKeyboard(notification: NSNotification) {
    let keyboardFrame = notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
    let keyboardHeight = keyboardFrame.CGRectValue().height

    tableView.contentInset.bottom = keyboardHeight
    tableView.scrollIndicatorInsets.bottom = keyboardHeight

    keyboardShowing = true
}

func didHideKeyboard(notification: NSNotification) {
    keyboardShowing = false
}

func scrollViewDidScroll(scrollView: UIScrollView) {

    if !keyboardShowing {
        return
    }

    let toolbarFrame = view.convertRect(toolbar.frame, fromView: toolbar)

    tableView.scrollIndicatorInsets.bottom = view.bounds.height - toolbarFrame.minY
    tableView.contentInset.bottom = view.bounds.height - toolbarFrame.minY
}
like image 140
Paul Avatar answered Nov 15 '22 05:11

Paul