ios8uikeyboardnsnotificationiphone-softkeyboard

Using only UIKeyboardWillChangeFrameNotification notification


Considering the new QuickType section of the keyboard.

Is it quite true that one can use ONLY a notification for UIKeyboardWillChangeFrameNotification,

and simply "not bother with" the "older" UIKeyboardWillShowNotification and UIKeyboardWillHideNotification ?

Testing seems to show it works perfectly, using ONLY keyboardFrameDidChange - but we could be missing something?

BTW here's an example of how to use UIKeyboardWillChangeFrameNotification https://stackoverflow.com/a/26226732/294884


Solution

  • Updated for Swift 5 on 2021-05-17

    It is definitely possible and can cut your code just about in half. The following example uses Auto Layout for a lot of the heavy lifting.

    NotificationCenter.default.addObserver(
        forName: UIResponder.keyboardWillChangeFrameNotification,
        object: nil,
        queue: nil
    ) { (notification) in
        guard let userInfo = notification.userInfo,
              let frameEnd = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
              let curveRaw = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int,
              let curve = UIView.AnimationCurve(rawValue: curveRaw),
              let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval
        else { return }
    
        // Convert the frame rects you're interested in to a common coordinate space
        let keyboardRect = self.view.convert(frameEnd, from: nil)
        let formContainerRect = self.view.convert(self.formContainerView.frame, from: nil)
    
        // Calculate their intersection and adjust your constraints accordingly
        let intersection = keyboardRect.intersection(formContainerRect)
        if !intersection.isNull {
            // Some overlap; adjust the bottom of your views (what you do here will vary)
            self.formContainerBottomConstraint?.constant = intersection.size.height
        } else {
            // No overlap; reset your views to their default position
            self.formContainerBottomConstraint?.constant = 0
        }
    
        let animator = UIViewPropertyAnimator.init(duration: duration, curve: curve) {
            self.view.layoutIfNeeded()
        }
        animator.startAnimation()
    }
    

    self.formContainerBottomConstraint is a NSLayoutConstraint that binds the bottom of my (imaginary) form to the bottom of my view. This code animates the field up when the keyboard appears and down when it disappears.

    All of that was possible in iOS < 8 by using a combination of UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. But! As you say, iOS 8 introduced the QuickType section which can be collapsed or expanded by the user. This solution is super versatile and will let your app respond to whatever keyboard changes the OS throws your way.