Linus Bicker
Linus Bicker

Reputation: 129

Swift- Adjusting Constraints to allow for keyboard

I'm a new SWIFT programmer learning to code as a hobby. I'm near done my first app and have a tableview in which part of the cell contains a textfield where the user can edit the data contained therein.

When the user clicks in the textfield, the keyboard pops up and obscures much of the tableview.

I've researched this and have been studying for the last hour the realm of solutions, but I'm a little stuck on where to start. As best I can tell, I should just adjust the constraint on tableview such that it isn't 0 from the bottom of the view but rather how many ever pixels it is that is the height of the keyboard.

So I understand the concept but don't know how to execute these 2 big parts:

  1. how do I set up a listener so that when the keyboard appears I can run some code
  2. how do I programmatically set the constraints of my tableview?

Upvotes: 0

Views: 788

Answers (1)

elarcoiris
elarcoiris

Reputation: 1976

You'll want to attach some observers in your viewDidLoad:

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

Remember to remove them in viewWillDisappear:

NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)

You'll need an @objc function for your observer to call:

@objc private func keyboardWillChange(_ notification: Notification) {
        guard let userInfo = (notification as Notification).userInfo, let value = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
            return
        }
    
    if ((userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification
        var newHeight: CGFloat
        let textHeight = inputTextView.textContainer.size.height
        
        if isKeyboardShowing {
            newHeight = value.cgRectValue.height - view.safeAreaInsets.bottom
            bottomConstraint.constant = newHeight + textHeight
            view.bringSubviewToFront(messageInputContainerView)
            UIView.animate(withDuration: 0, delay: 0,
                               options: .curveEaseOut,
                               animations: { self.view.layoutIfNeeded() },
                               completion: nil)
        }
        else {
            view.bringSubviewToFront(messageInputContainerView) 
            newHeight = value.cgRectValue.height - view.safeAreaInsets.bottom
            bottomConstraint?.constant = view.safeAreaInsets.bottom + messageInputContainerView.bounds.height - textHeight
            UIView.animate(withDuration: 0,
                           delay: 0,
                           options: .curveEaseOut,
                           animations: { self.view.layoutIfNeeded() },
                           completion: nil)
        }
    }
}

bottomConstraint is your class reference here in this case attached to the bottom of the tableView on storyboard and is our movable baseline when the keyboard is open and closed. You will need to tweak the values and constraint choices for your own use case/sizes. messageInputContainerView is the container for our inputTextView in this example.

Upvotes: 1

Related Questions