ScrollView and keyboard in Swift

Solution 1:

In ViewDidLoad, register the notifications:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:UIResponder.keyboardWillHideNotification, object: nil)

Add below observer methods which does the automatic scrolling when keyboard appears.

@objc func keyboardWillShow(notification:NSNotification) {

    guard let userInfo = notification.userInfo else { return }
    var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    keyboardFrame = self.view.convert(keyboardFrame, from: nil)

    var contentInset:UIEdgeInsets = self.scrollView.contentInset
    contentInset.bottom = keyboardFrame.size.height + 20
    scrollView.contentInset = contentInset
}

@objc func keyboardWillHide(notification:NSNotification) {

    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    scrollView.contentInset = contentInset
}

Solution 2:

The top answer for swift 3:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil)

And then:

func keyboardWillShow(notification:NSNotification){
    //give room at the bottom of the scroll view, so it doesn't cover up anything the user needs to tap
    var userInfo = notification.userInfo!
    var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    keyboardFrame = self.view.convert(keyboardFrame, from: nil)

    var contentInset:UIEdgeInsets = self.theScrollView.contentInset
    contentInset.bottom = keyboardFrame.size.height
    theScrollView.contentInset = contentInset
}

func keyboardWillHide(notification:NSNotification){
    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    theScrollView.contentInset = contentInset
}

Solution 3:

Here is a complete solution, utilizing guard and concise code. Plus correct code in keyboardWillHide to only reset the bottom to 0.

@IBOutlet private weak var scrollView: UIScrollView!

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerNotifications()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    scrollView.contentInset.bottom = 0
}

private func registerNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc private func keyboardWillShow(notification: NSNotification){
    guard let keyboardFrame = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
    scrollView.contentInset.bottom = view.convert(keyboardFrame.cgRectValue, from: nil).size.height
}

@objc private func keyboardWillHide(notification: NSNotification){
    scrollView.contentInset.bottom = 0
}

Solution 4:

for Swift 4.0

In ViewDidLoad

// setup keyboard event
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

Add below observer methods which does the automatic scrolling when keyboard appears.

@objc func keyboardWillShow(notification:NSNotification){
    var userInfo = notification.userInfo!
    var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    keyboardFrame = self.view.convert(keyboardFrame, from: nil)

    var contentInset:UIEdgeInsets = self.ui_scrollView.contentInset
    contentInset.bottom = keyboardFrame.size.height
    ui_scrollView.contentInset = contentInset
}

@objc func keyboardWillHide(notification:NSNotification){

    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    ui_scrollView.contentInset = contentInset
}