Explorer
Explorer

Reputation: 75

Pushing UIViews up for UIKeyboard

I've added a willShow and willHide observer for the keyboard and am trying to push up the bottom UITextView up to adjust to the UIKeyboard showing. However, my keyboard is getting pushed farther up than just the keyboard frame height. How do I constrain the UITextView bottom anchor to the top of the keyboard?

// Observer method
@objc func handleKeyboardNotification(_ notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
        let isKeyboardShowing = (notification.name == UIResponder.keyboardWillShowNotification)

        // Push views up if keyboard is showing, otherwise set constant back to 0
        messageInputBottomAnchor?.constant = isKeyboardShowing ? -(keyboardFrame?.height)! : 0

        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
}

Picture illustrating the problem

Upvotes: 1

Views: 111

Answers (2)

Explorer
Explorer

Reputation: 75

I left my UITextView constrained to the safeAreaLayoutGuide bottom but I added a CGFloat to represent the padding at the bottom of the screen. It defaulted as 0 but if iOS 11 was available (to account for the iPhone X and it's bottom padding), I set the CGFloat to UIApplication.shared.keyWindow!.safeAreaInsets.bottom. Then, when I moved the UITextView up or down according to the UIKeyboard, I subtracted the size of the CGFloat.

//Global var 
var safeAreaBottom: CGFloat = 0.0

// Verify screen bottom in viewDidLoad
if #available(iOS 11, *) {
   safeAreaBottom = UIApplication.shared.keyWindow!.safeAreaInsets.bottom
}

// Push views up if keyboard is showing, otherwise set constant back to 0. Subtract safeAreaBottom if iOS 11 is available to compensate for the bottom padding
   textViewBottomAnchorToSafeArea?.constant = isKeyboardShowing ? -((keyboardFrame?.height)! - safeAreaBottom) : 0

Upvotes: 0

A Han
A Han

Reputation: 11

What I did was

  • I created 2 different constraints on the UITextView, one to the superview and one to the safearea.
  • Connect both of those constraints over to the view controller and make sure that they are not weak references.
  • In viewDidLoad, make sure that the safearea constraint is active and the superview constraint isn't.
  • In your listeners when the keyboard comes up, switch the isActive fields of the constraints so now the superview one is active and safearea is inactive.
  • In the listener when it's going to resign, switch them back.

The reason for needing to make sure that the references aren't weak is because when you set the isActive field to false, it'll actually remove it and if you try and reference the constraint later, you'll find yourself trying to access a member of a nil object.

Upvotes: 1

Related Questions