Skip to content

Instantly share code, notes, and snippets.

@scotteg
Last active March 1, 2019 16:33
Show Gist options
  • Save scotteg/1f1c027a229fca6b723993000f69152c to your computer and use it in GitHub Desktop.
Save scotteg/1f1c027a229fca6b723993000f69152c to your computer and use it in GitHub Desktop.
Drop-in keyboard handler
//
// HandlesKeyboard.swift
//
// Created by Scott Gardner on 1/14/19.
// Copyright © 2019 Scott Gardner. All rights reserved.
//
import UIKit
protocol HandlesKeyboard where Self: UIViewController {
var bottomConstraintForKeyboardHandling: NSLayoutConstraint! { get }
func startHandlingKeyboardChanges()
func stopHandlingKeyboardChanges()
}
extension HandlesKeyboard {
/// Registers caller to start handling keyboard will show and will hide notifications
/// - Warning: Caller *must* implement `stopHandlingKeyboardChanges()` to unregister, e.g., in `deinit`
/// ```
/// func stopHandlingKeyboardChanges() {
/// NotificationCenter.default.removeObserver(self)
/// }
///
/// deinit {
/// stopHandlingKeyboardChanges()
/// }
/// ```
func startHandlingKeyboardChanges() {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { [weak self] in
self?.updateBottomConstraint(notification: $0)
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { [weak self] in
self?.updateBottomConstraint(notification: $0)
}
}
// Intentionally not implemented to ensure caller unregisters
// func stopHandlingKeyboardChanges() {
// NotificationCenter.default.removeObserver(self)
// }
func updateBottomConstraint(notification: Notification) {
guard let userInfo = notification.userInfo,
let animationDuration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue,
let keyboardEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let rawAnimationCurve = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value
else { return }
if notification.name == UIResponder.keyboardWillHideNotification {
bottomConstraintForKeyboardHandling.constant = 0.0
} else {
bottomConstraintForKeyboardHandling.constant = view.bounds.maxY - view.convert(keyboardEndFrame, to: view.window).minY
}
let animationCurve = UIView.AnimationOptions(rawValue: UInt(rawAnimationCurve << 16))
UIView.animate(withDuration: animationDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { [weak self] in
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment