Peter R
Peter R

Reputation: 3516

swift / iOS - Keyboard height value changes between notifications, but actual height remains the same

I have a view I'm trying to move when the keyboard appears/disappears. Here's the basic code.

   func registerForKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: .UIKeyboardDidShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: .UIKeyboardDidHide, object: nil)
    }

    @objc func keyboardWasShown(_ notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0 {
                print("\n\n\n\(keyboardSize.height)\n\n")
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
    }

@objc func keyboardWillBeHidden(_ notification: NSNotification) {
        self.view.frame.origin.y = 0
    }

The first time it get's called, it prints 258.0, and the view moves up. Subsequent calls print 216.0. The keyboard moves up the same amount each time. The first time it moves the view the correct amount (the bottom the view is just above the keyboard), subsequent times the bottom part (42px) is behind the keyboard.

Any idea what might cause this?

Upvotes: 3

Views: 1404

Answers (1)

Harsh
Harsh

Reputation: 2908

Instead of the UIKeyboardFrameBeginUserInfoKey, use UIKeyboardFrameEndUserInfoKey.

Moreover I would suggest you to use just one notification to handle all the changes to the frame as follows:

    //Add keyboard did Layout change notification
    NotificationCenter.default.addObserver(self,selector: #selector(self.keyboardNotification(notification:)),name:NSNotification.Name.UIKeyboardWillChangeFrame,object: nil)

And then implement it like this

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            //Change This
            //self.signInButtonBottomConstraint?.constant = 0.0
        } else {
            //Modify This
            //self.signInButtonBottomConstraint?.constant -= (endFrame?.size.height ?? 0.0)
        }
        UIView.animate(withDuration: duration,
                       delay: TimeInterval(0),
                       options: animationCurve,
                       animations: { self.view.layoutIfNeeded() },
                       completion: nil)
    }

Upvotes: 6

Related Questions