Last active
September 6, 2022 19:42
-
-
Save roymckenzie/35684bf3ae6df02f60a41490a9843008 to your computer and use it in GitHub Desktop.
Easy way to get your view controllers to respect appearance of the keyboard.
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
// KeyboardAvoidable | |
// Roy McKenzie | |
protocol KeyboardAvoidable: class { | |
func addKeyboardObservers(customBlock: ((CGFloat) -> Void)?) | |
func removeKeyboardObservers() | |
var layoutConstraintsToAdjust: [NSLayoutConstraint] { get } | |
} | |
var KeyboardShowObserverObjectKey: UInt8 = 1 | |
var KeyboardHideObserverObjectKey: UInt8 = 2 | |
extension KeyboardAvoidable where Self: UIViewController { | |
var keyboardShowObserverObject: NSObjectProtocol? { | |
get { | |
return objc_getAssociatedObject(self, | |
&KeyboardShowObserverObjectKey) as? NSObjectProtocol | |
} | |
set { | |
objc_setAssociatedObject(self, | |
&KeyboardShowObserverObjectKey, | |
newValue, | |
.OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
} | |
var keyboardHideObserverObject: NSObjectProtocol? { | |
get { | |
return objc_getAssociatedObject(self, | |
&KeyboardHideObserverObjectKey) as? NSObjectProtocol | |
} | |
set { | |
objc_setAssociatedObject(self, | |
&KeyboardHideObserverObjectKey, | |
newValue, | |
.OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
} | |
func addKeyboardObservers(customBlock: ((CGFloat) -> Void)? = nil) { | |
keyboardShowObserverObject = NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, | |
object: nil, | |
queue: nil) { [weak self] notification in | |
guard let height = self?.getKeyboardHeightFrom(notification: notification) else { return } | |
if let customBlock = customBlock { | |
customBlock(height) | |
return | |
} | |
self?.layoutConstraintsToAdjust.forEach { | |
$0.constant = height | |
} | |
UIView.animate(withDuration: 0.2){ | |
self?.view.layoutIfNeeded() | |
} | |
} | |
keyboardHideObserverObject = NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, | |
object: nil, | |
queue: nil) { [weak self] notification in | |
if let customBlock = customBlock { | |
customBlock(0) | |
return | |
} | |
self?.layoutConstraintsToAdjust.forEach { | |
$0.constant = 0 | |
} | |
UIView.animate(withDuration: 0.2){ | |
self?.view.layoutIfNeeded() | |
} | |
} | |
} | |
private func getKeyboardHeightFrom(notification: Notification) -> CGFloat { | |
guard let info = notification.userInfo else { return .leastNormalMagnitude } | |
guard let value = info[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return .leastNormalMagnitude } | |
let keyboardSize = value.cgRectValue.size | |
return keyboardSize.height | |
} | |
func removeKeyboardObservers() { | |
if let keyboardShowObserverObject = keyboardShowObserverObject { | |
NotificationCenter.default.removeObserver(keyboardShowObserverObject) | |
} | |
if let keyboardHideObserverObject = keyboardHideObserverObject { | |
NotificationCenter.default.removeObserver(keyboardHideObserverObject) | |
} | |
keyboardShowObserverObject = nil | |
keyboardHideObserverObject = nil | |
} | |
} | |
// 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 layoutConstraintsToAdjust: [NSLayoutConstraint] { | |
// return [scrollViewBottomConstraint] | |
// } | |
// } |
Updated this to handle the opaque objects created by the addObserver
methods and remove observers from them when calling removeKeyboardObservers
. Also Swift 3 goodness. Also custom callback...
Don't removeKeyboardObservers() should be called on the beginning of addKeyboardObservers() to prevent issues when it was called more than once?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great point @MoridinBG. Working a bit with @Nadohs we came up with this solution to clean up the notifications per your comment:
https://gist.github.com/roymckenzie/05bb47a3d8526eeedeffe6e42a0c178c