Skip to content

Instantly share code, notes, and snippets.

@wangdu1005
Last active September 27, 2018 04:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wangdu1005/d08b4c0ca7ec97153cc11baf3481b2ce to your computer and use it in GitHub Desktop.
Save wangdu1005/d08b4c0ca7ec97153cc11baf3481b2ce to your computer and use it in GitHub Desktop.
KeyboardHandler
import UIKit
enum KeyboardDirection {
case none
case up
case down
}
struct KeyboardFrameDelta {
var height: CGFloat = 0
var y: CGFloat = 0
var direction: KeyboardDirection = .none
}
struct KeyboardHandler {
var willMoveUp: ((KeyboardFrameDelta) -> Void)?
var willMoveDown: ((KeyboardFrameDelta) -> Void)?
var info: [AnyHashable: Any]?
var willMoveUsedView: Bool = true
func handle(using view: UIView, with animation: ((KeyboardFrameDelta) -> Void)? = nil) {
guard let userInfo = info,
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
let frameEnd = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue,
let frameBegin = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue,
let window = view.window,
let superview = view.superview else {
return
}
print(frameEnd.cgRectValue.size.height, frameBegin.cgRectValue.size.height, separator: " ... ")
let rectEnd = frameEnd.cgRectValue
let rectBegin = frameBegin.cgRectValue
let options = UIViewAnimationOptions(rawValue: curve << 16)
let rectWindow = view.convert(CGRect.zero, to: nil)
var insetBottom = window.bounds.size.height - rectWindow.origin.y
var delta = KeyboardFrameDelta()
delta.direction = direction(end: frameEnd, begin: frameBegin)
delta.height = rectEnd.size.height - rectBegin.size.height
delta.y = rectEnd.origin.y - rectBegin.origin.y
switch delta.direction {
case .up:
insetBottom -= view.bounds.size.height
delta.y += insetBottom
willMoveUp?(delta)
case .down:
insetBottom += view.frame.origin.y
insetBottom -= superview.bounds.size.height
delta.y -= insetBottom
willMoveDown?(delta)
default:
break
}
UIView.animate(
withDuration: duration,
delay: 0,
options: options,
animations: {
if self.willMoveUsedView {
if delta.height == 0 {
view.frame.origin.y += delta.y
} else {
view.frame.origin.y -= delta.height
}
}
animation?(delta)
},
completion: nil
)
}
private func direction(end frameEnd: NSValue, begin frameBegin: NSValue) -> KeyboardDirection {
let rectEnd = frameEnd.cgRectValue
let rectBegin = frameBegin.cgRectValue
if rectEnd.origin.y < rectBegin.origin.y {
return .up
} else if rectEnd.origin.y > rectBegin.origin.y {
return .down
} else {
return .none
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment