Skip to content

Instantly share code, notes, and snippets.

@stucarney
Last active November 14, 2020 15:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stucarney/f6e87cc37541ee8d0408653b528dc195 to your computer and use it in GitHub Desktop.
Save stucarney/f6e87cc37541ee8d0408653b528dc195 to your computer and use it in GitHub Desktop.
iOS / Swift: Keyboard Show/Hide Animations for Views in a UIViewController
/**
Gathers all the data defined in `Keyboard Notification User Info Keys` from
a keyboard will/did show/hide `NSNotification` into an easier to use tuple.
- parameter notification: A notification resulting from a keyboard appearance notification,
e.g. `UIKeyboardWillShowNotification`
- returns: A tuple of data about the keyboard appearance extracted from the notification user info.
*/
public func keyboardInfoFromNotification(_ notification: Notification) -> (beginFrame: CGRect, endFrame: CGRect, animationCurve: UIViewAnimationOptions, animationDuration: Double) {
let userInfo = (notification as NSNotification).userInfo!
let beginFrameValue = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let endFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue
let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber
return (
beginFrame: beginFrameValue.cgRectValue,
endFrame: endFrameValue.cgRectValue,
animationCurve: UIViewAnimationOptions(rawValue: UInt(animationCurve.uintValue << 16)),
animationDuration: animationDuration.doubleValue)
}
class ViewController: UIViewController {
// MARK: - Keyboard Outlets and Properties
// This should be an invisible UIView with a bottom layout constraint aligned with bottom layout Guide,
// and a top layout constraint aligned with where the keyboard should not go above.
// NOTE: disable UserInteraction, to allow taps through this view
@IBOutlet weak var keyboardPlacementView: UIView!
@IBOutlet weak var keyboardOffsetConstraint: NSLayoutConstraint! // Y offset or Height, that moves all attached views up/down
var keyboardInitialOffsetConstraintConstant: CGFloat = 0.0 // Set in ViewDidLoad
let constraintDirection: CGFloat = -1 // -1 (offset up when keyboard appears) OR 1 (offsets down when keyboard appears)
// MARK: - UIViewController Methods
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.keyboardWillShow(_:)),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.keyboardWillHide(_:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
keyboardInitialOffsetConstraintConstant = keyboardOffsetConstraint.constant
}
// MARK: Keyboard
func keyboardWillShow(_ note: Notification) {
let keyboardData = keyboardInfoFromNotification(note)
let offsetHeight = keyboardData.endFrame.size.height
let offsetDifferenceToPlacementView = offsetHeight - keyboardPlacementView.frame.height
if offsetDifferenceToPlacementView > 0 {
self.view.layoutIfNeeded()
let initialConstraintConstant = keyboardInitialOffsetConstraintConstant
weak var constraint = keyboardOffsetConstraint
let direction = constraintDirection
weak var weakSelf = self
UIView.animate(withDuration: keyboardData.animationDuration,
delay: 0,
options: keyboardData.animationCurve,
animations: {
constraint?.constant = (direction * offsetDifferenceToPlacementView) + initialConstraintConstant
weakSelf?.view.layoutIfNeeded()
},
completion: nil)
}
}
func keyboardWillHide(_ note: Notification) {
let keyboardData = keyboardInfoFromNotification(note)
self.view.layoutIfNeeded()
let initialConstraintConstant = keyboardInitialOffsetConstraintConstant
weak var constraint = keyboardOffsetConstraint
weak var weakSelf = self
UIView.animate(withDuration: keyboardData.animationDuration,
delay: 0,
options: keyboardData.animationCurve,
animations: {
constraint?.constant = initialConstraintConstant
weakSelf?.view.layoutIfNeeded()
}, completion: nil)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment