Isuru
Isuru

Reputation: 31283

UIScrollView doesn't move the view properly when the keyboard appears

I have a view controller with a UIScrollView pinned to all 4 sides. Then a UIView inside with all its 4 sides pinned to the scroll view and as well as equal width and equal height constraints added.

Inside this view, there are two container views. These two container views embed two separate UITableViewControllers. I'm getting no auto layout errors or warnings.

enter image description here

This is how it looks when it's run.

enter image description here enter image description here

In the bottom table view, one cell(middle one of the first section) has a UITextField and the bottom cell has a UITextView. So obviously when the keyboard appears, these fields get obscured.

So what I wanted to do was to move the entire view that contains both container views when the keyboard appears. That's why I embedded it inside a scrollview. I use this code to monitor keyboard showing/hiding and set the scrollview's content inset accordingly.

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardWillShow(notification: NSNotification) {
        adjustInsetForKeyboard(true, notification: notification)
    }

    func keyboardWillHide(notification: NSNotification) {
        adjustInsetForKeyboard(false, notification: notification)
    }

    func adjustInsetForKeyboard(show: Bool, notification: NSNotification) {
        let userInfo = notification.userInfo ?? [:]
        let keybaordFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
        let adjustmentHeight = (CGRectGetHeight(keybaordFrame)) * (show ? 1 : -1)
        scrollView.contentInset.bottom += adjustmentHeight
    }

}

But there are a couple of issues.

  1. When the keyboard appears and although I change the scrollview's content inset, the entire view doesn't move. It does this weird thing. The bottom tableview goes under the top table view. It's easier to show so here is a video.

Tableviews overlapping issue

  1. When I refocus on a textfield for more than 1 time, the scrollview goes off the screen!

Tableview going off the screen

Anyone got an idea why this is happening?

Dropbox link to demo project

Upvotes: 0

Views: 550

Answers (2)

ruslan.musagitov
ruslan.musagitov

Reputation: 2124

There are couple ways:

  1. To observe UIKeyboadWillShowNotification and UIKeyboardWillHideNotification, get keyboard size data from it and adjust your scrollView contentInset bottom value properly.

    func viewDidAppear() {
        super.viewDidAppear()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "increaseContentInset:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "decreaseContentInset:", name: UIKeyboardWillHideNotification, object: nil)
    }
    
    func viewDidDisappear(){
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    func increaseContentInset(notification: NSNotification) {
        let endRect = notification.userInfo![UIKeyboardFrameEndUserInfoKey]
        scrollView.contentInset = UIEdgeInsetsMake(0, 0, CGRectGetHeight(endRect), 0)
    }
    
    func decreaseContentInset(notification: NSNotification) {
        scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    }
    
  2. Use the library for it. I strongly recommend you to use TPKeyboardAvoiding

Upvotes: 0

user1169629
user1169629

Reputation: 467

A UITableViewController already automatically handles the adjustment of the content inset when the keyboard is shown. There is no documented way to disable this behaviour. You can override viewWillAppear(animated: Bool) in your StaticTableViewController and not call it's super method:

override func viewWillAppear(animated: Bool) {
}

It's probably where the UITableViewController registers for the keyboard events, as this disables the content inset adjustment. However, I can't tell you if there will be other adverse effects of not calling viewWillAppear of UITableViewController and this behaviour might change with future versions of iOS. So a safer way is to just not use UITableViewController and add a standard UITableView to a UIViewController and load your cells in there.

Also note that with your design the user could scroll all the way up and hide your lower content view behind the keyboard. Then the user can't scroll down as any scrolling only scrolls and bounces the upper tableview. So rethink your design or hide the keyboard as soon as the user scrolls

Upvotes: 1

Related Questions