How do you adjust your scrollview to compensate for a keyboard vertically? Read on...
Yes I know this is some basic info, but I randomly noticed today that all of the answers I saw about this topic are all over the place with info, versions and/or use bangs all over the place... but nothing solid for Swift 3+.
The best way to do this is to place your content inside a UIScrollView, then adjust the scroll view's contentInset property by the height of the keyboard when it's shown. Absolutely do not assume the keyboard height--use the value from the "keyboard will show" notification.
Swift. You can get the keyboard height by subscribing to the UIKeyboardWillShowNotification notification.
Swift 4.2:
Substitute scrollView for UITableView, UICollectionView, etc.
let scrollView = UIScrollView()
Add observers.
override open func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
}
Add some functions to listen for the notifications:
@objc func keyboardWillHide(notification: Notification) {
let contentInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
@objc func keyboardWillShow(notification: Notification) {
guard let keyboardFrame: CGRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
scrollView.contentInset.bottom = keyboardFrame.height
}
Worth noting is that if your deployment target is iOS 9 or greater, you don't need to remove the observer anymore. Check the NotificationCenter docs for more info.
deinit {
NotificationCenter.default.removeObserver(self)
}
Swift 3:
let scrollView = UIScrollView()
Add observers.
override open func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(noti:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
NSNotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(noti:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
}
Add some functions to listen for the notifications:
func keyboardWillHide(noti: Notification) {
let contentInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
func keyboardWillShow(noti: Notification) {
guard let userInfo = noti.userInfo else { return }
guard var keyboardFrame: CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue else { return }
keyboardFrame = self.view.convert(keyboardFrame, from: nil)
var contentInset:UIEdgeInsets = scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
scrollView.contentInset = contentInset
}
Worth noting is that if your deployment target is iOS 9 or greater, you don't need to remove the observer anymore. Check the NotificationCenter docs for more info.
deinit {
NotificationCenter.default.removeObserver(self)
}
A modification to make it work on iOS 11 is to use UIKeyboardFrameEndUserInfoKey
rather than UIKeyboardFrameBeginUserInfoKey
. Just a simplified approach to @crewshin's solution:
@objc func keyboardWillShow(_ notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
scrollView.contentInset.bottom = keyboardSize.height
}
}
@objc func keyboardWillHide(_ notification: NSNotification) {
scrollView.contentInset.bottom = 0
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With