Created
August 21, 2016 22:08
-
-
Save aryaxt/6f747e9982445b8d90ee90cadf3707cc to your computer and use it in GitHub Desktop.
KeyboardManager
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
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