2

I have a UIView container which holds a UITextField and two UIButtons (see image below).

I have written an extension which listens to a UIKeyboardWillShow notification and animates the UIView so that it binds to the keyboard when it shows.

This works perfectly, but as soon as I start typing the UIView disappears again.

Extension usage:

sendMessageView.bindToKeyboard()

UIView extension:

extension UIView {

    func bindToKeyboard() {

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

    }//end func

    @objc func keyboardWillShow(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double

        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt

        let beginningFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue

        let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

        let deltaY = endFrame.origin.y - beginningFrame.origin.y


        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.frame.origin.y += deltaY
        }, completion: nil)

    }//end func

}//end extension

UIView binds to keyboard when it is displayed:

enter image description here

UIView disappears (I suspect behind the keyboard to its original location) when typing:

enter image description here

Roggie
  • 1,157
  • 3
  • 16
  • 40
  • Can you throw a couple of print statements in there to see how many times your function is called? Also, I want to point out, as a friendly tip, that if you add observers, it's good practice to remove them as well. I would write an extension that does that on deinit or something. – MegaTyX Jul 31 '18 at 02:57
  • I put a `print("bindToKeyboard() called...")` statement in my `bindToKeyboard()` function and it is called once only when `viewDidLoad()` runs. It is not called again even after I tap into the text field to bring up keyboard. ps: thanks for the tip re: removing notifications. – Roggie Jul 31 '18 at 03:05
  • Did you place it in the `keyboardWillShow(notification: NSNotification)` – MegaTyX Jul 31 '18 at 03:07
  • this time I did, I added `print("keyboardWillShow() called...")` and it is called once when I tap on the textfield, but as soon as I start to type the view disappears. – Roggie Jul 31 '18 at 03:12
  • I was thinking that maybe your view position was recalculated when keyboardWillShow() was called and maybe it was being called multiple times. Keeping in mind that the top of the keyboard will change when the user types, I will keep checking around. – MegaTyX Jul 31 '18 at 03:16
  • I have put constraints on the `UIView` via the storyboard to pin it left, right and bottom, would this be causing an issue perhaps, you think? – Roggie Jul 31 '18 at 03:17
  • Most definitely. Especially if you've pinned the top and bottom to other objects. I found something that may give you the same effect that you are looking for. Maybe you could take a look. https://stackoverflow.com/questions/35689528/add-a-view-on-top-of-the-keyboard-using-inputaccessoryview-swift – MegaTyX Jul 31 '18 at 03:20

1 Answers1

0

Don't put an extension for the UIView itself. Just add your textBox view as a subview and set the bottom constraint of your view to be updating according to the height of the keyboard. If keyboard is present, set the constant to the negative value of height of the keyboard else set it to zero.

    private func setupView() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardShown(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        self.view.backgroundColor = .white
        self.view.addSubview(textInputView)
        bottomConstraint = NSLayoutConstraint(item: textInputView, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1.0, constant: 0)
        NSLayoutConstraint.activate([
            //textBox.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0),
            //textInputView.heightAnchor.constraint(equalToConstant: UIFont.systemFontSize+14+10),
            textInputView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0),
            textInputView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0)
        ])
        bottomConstraint.isActive = true
    }

    @objc private func keyBoardShown(_ notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            print(keyboardSize.height)
            bottomConstraint.constant = -keyboardSize.height
            UIView.animate(withDuration: 0.5,
                           delay: TimeInterval(0),
                           options: .beginFromCurrentState,
                           animations: { self.view.layoutIfNeeded() },
                           completion: nil)
        }
    }