I tried to create a universal mechanism that could respond to a keyboard that displays and hides in iOS. I came up with a simple protocol and its extension, which does not contain real animations, but pulls them out of the object that accepts this protocol:
import UIKit
protocol KeyboardAnimatable {
func keyboardWillShowAnimation() -> (() -> Void)?
func keyboardWillHideAnimation() -> (() -> Void)?
}
extension KeyboardAnimatable where Self: UIViewController {
func setupKeyboardNotifcationListeners() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func removeKeyboardNotificationListeners() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
let userInfo = notification.userInfo as! Dictionary<String, AnyObject>
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSTimeInterval
let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.intValue
let curveAnimationOption = UIViewAnimationOptions(rawValue: UInt(animationCurve))
let options: UIViewAnimationOptions = [.BeginFromCurrentState, curveAnimationOption]
if let animation = keyboardWillShowAnimation() {
UIView.animateWithDuration(animationDuration, delay: 0, options: options, animations: animation, completion: nil)
}
}
func keyboardWillHide(notification: NSNotification) {
let userInfo = notification.userInfo as! Dictionary<String, AnyObject>
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSTimeInterval
let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.intValue
let curveAnimationOption = UIViewAnimationOptions(rawValue: UInt(animationCurve))
let options: UIViewAnimationOptions = [.BeginFromCurrentState, curveAnimationOption]
if let animation = keyboardWillHideAnimation() {
UIView.animateWithDuration(animationDuration, delay: 0, options: options, animations: animation, completion: nil)
}
}
}
I explicitly use the sentence wherein extension KeyboardAnimatable where Self: UIViewControllerto narrow it down so I can use it selfwhen adding watchers. Now I can create a view controller that accepts this protocol and, for example, changing the restrictions when the keyboard appears:
import UIKit
class ViewController: UIViewController, KeyboardAnimatable {
@IBOutlet weak var constraintYCenter: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
setupKeyboardNotifcationListeners()
}
func keyboardWillShowAnimation() -> (() -> Void)? {
return {
self.constraintYCenter.constant = 100
self.view.layoutIfNeeded()
}
}
func keyboardWillHideAnimation() -> (() -> Void)? {
return nil
}
deinit {
removeKeyboardNotificationListeners()
}
}
But when I run this code, the application crashes with the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[KeyboardAnimatableDemo.ViewController keyboardWillShow:]:
unrecognized selector sent to instance 0x7fb429f192d0'
, keyboardWillShow:, .
, ViewController, ( ), .
, - self setupKeyboardNotifcationListeners(), , . func setupKeyboardNotifcationListeners(vc: UIViewController) vc self, .
UIViewController , , . - extension UIViewcontroller where Self: KeyboardAnimatable, , , Swift.
- - , ?