Last active
November 14, 2020 15:30
-
-
Save stucarney/f6e87cc37541ee8d0408653b528dc195 to your computer and use it in GitHub Desktop.
iOS / Swift: Keyboard Show/Hide Animations for Views in a UIViewController
This file contains 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
/** | |
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) | |
} |
This file contains 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
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