Skip to content

Instantly share code, notes, and snippets.

@roymckenzie
Last active August 29, 2016 12:36
Show Gist options
  • Save roymckenzie/05bb47a3d8526eeedeffe6e42a0c178c to your computer and use it in GitHub Desktop.
Save roymckenzie/05bb47a3d8526eeedeffe6e42a0c178c to your computer and use it in GitHub Desktop.
import UIKit
typealias KeyboardHeightDuration = (height: CGFloat, duration: Double)
// New notification type
let RemoveKeyboardNotifications = "RemoveKeyboardNotifications"
protocol KeyboardAvoidable: class {
var layoutConstraintsForKeyboard: [NSLayoutConstraint] { get }
func addKeyboardObservers()
func removeKeyboardObservers()
}
extension KeyboardAvoidable where Self: UIViewController {
func addKeyboardObservers() {
// Store returned observer one for willShow
let observerOne = NSNotificationCenter
.defaultCenter()
.addObserverForName(UIKeyboardWillShowNotification,
object: nil,
queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
// Store returned observer two for willHide
let observerTwo = NSNotificationCenter
.defaultCenter()
.addObserverForName(UIKeyboardWillHideNotification,
object: nil,
queue: nil) { [weak self] notification in
self?.keyboardWillHide(notification)
}
// Create an object holder for a new listener event
// that will be triggered in `removeKeyboardObservers`
var observerThree: NSObjectProtocol?
observerThree = NSNotificationCenter
.defaultCenter()
.addObserverForName(RemoveKeyboardNotifications,
object: nil,
queue: nil) { [weak observerOne, weak observerTwo] notification in
guard let observerOne = observerOne else { return }
// Remove observer for willShow from above
NSNotificationCenter
.defaultCenter()
.removeObserver(observerOne,
name: UIKeyboardWillShowNotification,
object: nil)
guard let observerTwo = observerTwo else { return }
// Remove observer for willHide from above
NSNotificationCenter
.defaultCenter()
.removeObserver(observerTwo,
name: UIKeyboardWillHideNotification,
object: nil)
guard let observerThree = observerThree else { return }
// Remove observer attached to this entire block that we previously setup space for
NSNotificationCenter
.defaultCenter()
.removeObserver(observerThree,
name: RemoveKeyboardNotifications,
object: nil)
}
}
func removeKeyboardObservers() {
// Trigger new notification
NSNotificationCenter
.defaultCenter()
.postNotificationName(RemoveKeyboardNotifications, object: nil)
}
private func keyboardWillShow(notification: NSNotification) {
guard var info = getKeyboardInfo(notification) else { return }
if let tabBarHeight = tabBarController?.tabBar.frame.height {
info.height -= tabBarHeight
}
animateConstraints(info.height, duration: info.duration)
}
private func keyboardWillHide(notification: NSNotification) {
guard let info = getKeyboardInfo(notification) else { return }
animateConstraints(0, duration: info.duration)
}
private func getKeyboardInfo(notification: NSNotification) -> KeyboardHeightDuration? {
guard let userInfo = notification.userInfo else { return nil }
guard let rect = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue() else { return nil }
guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue else { return nil }
return (rect.height, duration)
}
private func animateConstraints(constant: CGFloat, duration: Double) {
layoutConstraintsForKeyboard.forEach { c in
c.constant = constant
}
UIView.animateWithDuration(duration) {
self.view.layoutIfNeeded()
}
}
}
// Example Implementation
// final class NiceViewController: UIViewController {
//
// @IBOutlet weak var scrollViewBottomConstraint: NSLayoutConstraint!
//
// override func viewWillAppear(animated: Bool) {
// super.viewWillAppear(animated)
//
// addKeyboardObservers()
// }
//
// override func viewWillDisappear(animated: Bool) {
// super.viewWillDisappear(animated)
//
// removeKeyboardObservers()
// }
// }
//
// extension NiceViewController: KeyboardAvoidable {
//
// var layoutConstraintsForKeyboard: [NSLayoutConstraint] {
// return [scrollViewBottomConstraint]
// }
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment