This worked for me
TL;DR: self.view.safeAreaInsets.bottom returned 0. The key was to use UIApplication.shared.keyWindow.safeAreaInsets.bottom instead [Source].
Let replyField be the UITextField of interest.
1) Add the observers in viewDidLoad().
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)
2) Set global variables within the class as the constraints.
var textFieldBottomConstraintKeyboardActive : NSLayoutConstraint?
var textFieldBottomConstraintKeyboardInactive : NSLayoutConstraint?
3) Set the constraints in a function called in viewDidLoad.
let replyFieldKeyboardActiveConstraint = self.replyField.bottomAnchor.constraint(
equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -1 * Constants.DEFAULT_KEYBOARD_HEIGHT /* whatever you want, we will change with actual height later */ + UITabBar.appearance().frame.size.height
)
let replyFieldKeyboardInactiveConstraint = self.replyField.bottomAnchor.constraint(
equalTo: self.view.safeAreaLayoutGuide.bottomAnchor
)
self.textFieldBottomConstraintKeyboardActive = replyFieldKeyboardActiveConstraint
self.textFieldBottomConstraintKeyboardInactive = replyFieldKeyboardInactiveConstraint
self.textFieldBottomConstraintKeyboardActive?.isActive = false
self.textFieldBottomConstraintKeyboardInactive?.isActive = true
4) Define the keyboardWillShow and keyboardWillHide methods. They key here is how we define the heightOffset in the keyboardWillShow method.
@objc func keyboardWillShow(notification: NSNotification) {
guard let userinfo = notification.userInfo else {
return
}
guard let keyboardSize = userinfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return
}
let keyboardFrame = keyboardSize.cgRectValue
self.view.layoutIfNeeded()
let heightOffset = keyboardFrame.height - UITabBar.appearance().frame.height - (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0)
self.textFieldBottomConstraintKeyboardActive?.constant = -1 * heightOffset
self.textFieldBottomConstraintKeyboardActive?.isActive = true
self.textFieldBottomConstraintKeyboardInactive?.isActive = false
self.view.setNeedsLayout()
}
@objc func keyboardWillHide(notification: NSNotification) {
self.textFieldBottomConstraintKeyboardActive?.isActive = false
self.textFieldBottomConstraintKeyboardInactive?.isActive = true
}
UIKeyboardFrameEndUserInfoKey
should return height deducting the safe area insets. – Nanete