Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active October 6, 2023 14:45
Show Gist options
  • Star 57 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save kristopherjohnson/13d5f18b0d56b0ea9242 to your computer and use it in GitHub Desktop.
Save kristopherjohnson/13d5f18b0d56b0ea9242 to your computer and use it in GitHub Desktop.
Swift convenience wrapper for the userInfo values associated with a UIKeyboard notification
import UIKit
/// Wrapper for the NSNotification userInfo values associated with a keyboard notification.
///
/// It provides properties that retrieve userInfo dictionary values with these keys:
///
/// - UIKeyboardFrameBeginUserInfoKey
/// - UIKeyboardFrameEndUserInfoKey
/// - UIKeyboardAnimationDurationUserInfoKey
/// - UIKeyboardAnimationCurveUserInfoKey
public struct KeyboardNotification {
let notification: NSNotification
let userInfo: NSDictionary
/// Initializer
///
/// :param: notification Keyboard-related notification
public init(_ notification: NSNotification) {
self.notification = notification
if let userInfo = notification.userInfo {
self.userInfo = userInfo
}
else {
self.userInfo = NSDictionary()
}
}
/// Start frame of the keyboard in screen coordinates
public var screenFrameBegin: CGRect {
if let value = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue {
return value.CGRectValue()
}
else {
return CGRectZero
}
}
/// End frame of the keyboard in screen coordinates
public var screenFrameEnd: CGRect {
if let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
return value.CGRectValue()
}
else {
return CGRectZero
}
}
/// Keyboard animation duration
public var animationDuration: Double {
if let number = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber {
return number.doubleValue
}
else {
return 0.25
}
}
/// Keyboard animation curve
///
/// Note that the value returned by this method may not correspond to a
/// UIViewAnimationCurve enum value. For example, in iOS 7 and iOS 8,
/// this returns the value 7.
public var animationCurve: Int {
if let number = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber {
return number.integerValue
}
return UIViewAnimationCurve.EaseInOut.rawValue
}
/// Start frame of the keyboard in coordinates of specified view
///
/// :param: view UIView to whose coordinate system the frame will be converted
/// :returns: frame rectangle in view's coordinate system
public func frameBeginForView(view: UIView) -> CGRect {
return view.convertRect(screenFrameBegin, fromView: view.window)
}
/// End frame of the keyboard in coordinates of specified view
///
/// :param: view UIView to whose coordinate system the frame will be converted
/// :returns: frame rectangle in view's coordinate system
public func frameEndForView(view: UIView) -> CGRect {
return view.convertRect(screenFrameEnd, fromView: view.window)
}
}
// Example of using KeyboardNotification to update an NSLayoutConstraint
import UIKit
final class ViewController: UIViewController {
// Outlet for a layout constraint that specifies distance from bottom of
// a subview to the bottom of the view.
//
// This constraint will be updated when the keyboard appears, disappears,
// or changes size.
@IBOutlet weak var bottomLayoutConstraint: NSLayoutConstraint!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "keyboardWillChangeFrameNotification:",
name: UIKeyboardWillChangeFrameNotification,
object: nil)
}
override func viewDidDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
super.viewDidDisappear(animated)
}
func keyboardWillChangeFrameNotification(notification: NSNotification) {
let n = KeyboardNotification(notification)
let keyboardFrame = n.frameEndForView(self.view)
let animationDuration = n.animationDuration
let animationCurve = n.animationCurve
let viewFrame = self.view.frame
let newBottomOffset = viewFrame.maxY - keyboardFrame.minY
self.view.layoutIfNeeded()
UIView.animateWithDuration(animationDuration,
delay: 0,
options: UIViewAnimationOptions(rawValue: UInt(animationCurve << 16)),
animations: {
self.bottomLayoutConstraint.constant = newBottomOffset
self.view.layoutIfNeeded()
},
completion: nil
)
}
}
@kristopherjohnson
Copy link
Author

Example usage:

    // Adjust bottom vertical-space constraint when a
    // UIKeyboardWillChangeFrameNotification is received

    func keyboardWillChangeFrame(notification: NSNotification) {
        let keyboard = KeyboardNotification(notification: notification)

        let frameBegin = keyboard.frameBeginForView(view)
        let frameEnd = keyboard.frameEndForView(view)
        let originDelta = frameEnd.origin.y - frameBegin.origin.y

        bottomVerticalSpaceConstraint.constant -= originDelta
        view.setNeedsUpdateConstraints()

        let curve = keyboard.animationCurve

        UIView.animateWithDuration(keyboard.animationDuration,
            delay: 0.0,
            options: UIViewAnimationOptions(UInt(curve) << 16),
            animations: { self.view.layoutIfNeeded() },
            completion: nil)
    }

@joachimboggild
Copy link

Thanks a lot for this :-) These casts are really obscure...

@joachimboggild
Copy link

Minor correction:
line 78: Should be "end frame" instead of "start frame"...

@joachimboggild
Copy link

One more: Line 67: toRaw() is not working anymore. It should be:

    return UIViewAnimationCurve.EaseInOut.rawValue

@hpux735
Copy link

hpux735 commented Aug 23, 2015

This is very awesome. Thanks!!

@mark-anders
Copy link

Thanks so much for this, it works great!

@christ776
Copy link

This is great, I was getting the wrong height (258) and I didn't know why! thanks!

@nessup
Copy link

nessup commented Sep 20, 2017

Sad that Apple hasn't updated its keyboard API for Swift 3/4! Thank you so much for this gist.

@dhavalnenaagile
Copy link

dhavalnenaagile commented Nov 29, 2017

Thanks a lot !!

@eli7ah
Copy link

eli7ah commented May 6, 2018

All ingenious is simple. Thanx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment