Such simple UIViewController extension can be used
//MARK: - Observers extension UIViewController { func addObserverForNotification(notificationName: String, actionBlock: (NSNotification) -> Void) { NSNotificationCenter.defaultCenter().addObserverForName(notificationName, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: actionBlock) } func removeObserver(observer: AnyObject, notificationName: String) { NSNotificationCenter.defaultCenter().removeObserver(observer, name: notificationName, object: nil) } } //MARK: - Keyboard observers extension UIViewController { typealias KeyboardHeightClosure = (CGFloat) -> () func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?, willHide willHideClosure: KeyboardHeightClosure?) { NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { [weak self](notification) in if let userInfo = notification.userInfo, let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue(), let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double, let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt, let kFrame = self?.view.convertRect(frame, fromView: nil), let kBounds = self?.view.bounds { let animationType = UIViewAnimationOptions(rawValue: c) let kHeight = kFrame.size.height UIView.animateWithDuration(duration, delay: 0, options: animationType, animations: { if CGRectIntersectsRect(kBounds, kFrame) { // keyboard will be shown willShowClosure?(kHeight) } else { // keyboard will be hidden willHideClosure?(kHeight) } }, completion: nil) } else { print("Invalid conditions for UIKeyboardWillChangeFrameNotification") } }) } func removeKeyboardObserver() { removeObserver(self, notificationName: UIKeyboardWillChangeFrameNotification) } }
Example of usage
override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) removeKeyboardObserver() } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) addKeyboardChangeFrameObserver(willShow: { [weak self](height) in //Update constraints here self?.view.setNeedsUpdateConstraints() }, willHide: { [weak self](height) in //Reset constraints here self?.view.setNeedsUpdateConstraints() }) }
Swift 4 solution
//MARK: - Observers extension UIViewController { func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) { NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock) } func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) { NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil) } } //MARK: - Keyboard handling extension UIViewController { typealias KeyboardHeightClosure = (CGFloat) -> () func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?, willHide willHideClosure: KeyboardHeightClosure?) { NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: OperationQueue.main, using: { [weak self](notification) in if let userInfo = notification.userInfo, let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double, let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt, let kFrame = self?.view.convert(frame, from: nil), let kBounds = self?.view.bounds { let animationType = UIViewAnimationOptions(rawValue: c) let kHeight = kFrame.size.height UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: { if kBounds.intersects(kFrame) { // keyboard will be shown willShowClosure?(kHeight) } else { // keyboard will be hidden willHideClosure?(kHeight) } }, completion: nil) } else { print("Invalid conditions for UIKeyboardWillChangeFrameNotification") } }) } func removeKeyboardObserver() { removeObserver(self, notificationName: NSNotification.Name.UIKeyboardWillChangeFrame) } }
Swift 4.2
//MARK: - Keyboard handling extension UIViewController { func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) { NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock) } func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) { NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil) } typealias KeyboardHeightClosure = (CGFloat) -> () func removeKeyboardObserver() { removeObserver(self, notificationName: UIResponder.keyboardWillChangeFrameNotification) } func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?, willHide willHideClosure: KeyboardHeightClosure?) { NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, object: nil, queue: OperationQueue.main, using: { [weak self](notification) in if let userInfo = notification.userInfo, let frame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, let c = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt, let kFrame = self?.view.convert(frame, from: nil), let kBounds = self?.view.bounds { let animationType = UIView.AnimationOptions(rawValue: c) let kHeight = kFrame.size.height UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: { if kBounds.intersects(kFrame) { // keyboard will be shown willShowClosure?(kHeight) } else { // keyboard will be hidden willHideClosure?(kHeight) } }, completion: nil) } else { print("Invalid conditions for UIKeyboardWillChangeFrameNotification") } }) } }