Last active
August 29, 2016 12:36
-
-
Save roymckenzie/05bb47a3d8526eeedeffe6e42a0c178c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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