Skip to content

Instantly share code, notes, and snippets.

@aryaxt
Created August 21, 2016 22:08
Show Gist options
  • Save aryaxt/6f747e9982445b8d90ee90cadf3707cc to your computer and use it in GitHub Desktop.
Save aryaxt/6f747e9982445b8d90ee90cadf3707cc to your computer and use it in GitHub Desktop.
KeyboardManager
public class KeyboardManager {
public struct KeyboardChange {
public let visibleHeight: CGFloat
public let endFrame: CGRect
public let animationDuration: TimeInterval
public let animationOptions: UIViewAnimationOptions
}
public typealias KeyboardChangeClosure = (KeyboardChange)->Void
public var keyboardChangeClosure: KeyboardChangeClosure?
private var bottomConstraintsToBeManaged = [UIView: CGFloat]()
private var bottomInsetsToBeManaged = [UIScrollView: CGFloat]()
public init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(KeyboardManager.keyboardWillChangeFrameNotificationRecieved(notification:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: - Public -
public func setListener(keyboardChangeClosure: KeyboardChangeClosure) {
self.keyboardChangeClosure = keyboardChangeClosure
}
public func manageBottomConstraint(for view: UIView) {
let bottomConstraint = bottomConstraintFromView(view: view)
bottomConstraintsToBeManaged[view] = bottomConstraint?.constant ?? 0
}
public func manageBottomInset(for scrollView: UIScrollView) {
bottomConstraintsToBeManaged[scrollView] = scrollView.contentInset.bottom
}
// MARK: - Private -
private func bottomConstraintFromView(view: UIView) -> NSLayoutConstraint? {
return view.superview?.constraints.filter {
($0.firstItem === view || $0.secondItem === view) &&
($0.firstAttribute == .bottom || $0.secondAttribute == .bottom)
}.first
}
// MARK: - NSNotification -
@objc func keyboardWillChangeFrameNotificationRecieved(notification: NSNotification) {
if let userInfo = notification.userInfo,
let window = UIApplication.shared.keyWindow,
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let duration: TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber as TimeInterval??) ?? 0,
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber {
let animationCurveRaw = animationCurveRawNSN.uintValue
let animationCurve: UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
let y = endFrame.origin.y == CGFloat.infinity ? 0 : endFrame.origin.y
let height = endFrame.size.height == CGFloat.infinity ? 0 : endFrame.size.height
let offset: CGFloat = y + height - window.frame.size.height
let keyboardVisibleHeight = height - offset
let keyboardChange = KeyboardChange(
visibleHeight: keyboardVisibleHeight,
endFrame: endFrame,
animationDuration: duration,
animationOptions: animationCurve)
keyboardChangeClosure?(keyboardChange)
UIView.animate(
withDuration: keyboardChange.animationDuration,
delay: 0,
options: keyboardChange.animationOptions,
animations: {
for (view, bottom) in self.bottomConstraintsToBeManaged {
let bottomConstraint = self.bottomConstraintFromView(view: view)
bottomConstraint?.constant = bottom + keyboardChange.visibleHeight
}
for (scrollView, bottom) in self.bottomInsetsToBeManaged {
var inset = scrollView.contentInset
inset.bottom = bottom + keyboardChange.visibleHeight
scrollView.contentInset = inset
}
}, completion: nil)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment