Для экземпляров UIViewController вам необходимо наблюдать эти уведомления только тогда, когда вид видим и не подписываться на уведомление несколько раз.Лучший способ сделать это:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillChangeFrame(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
А вот рабочий код из моего проекта для обработки рамки из кейборда
@objc private func onKeyboardWillChangeFrame(_ notification: NSNotification) {
// extract values
if let userInfo = notification.userInfo,
let keyboardFrameEnd = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let animationCurveInt = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.intValue {
/*
СУКАБЛЯТЬ
With upgrate to Swift 4.2 UIView.AnimationCurve(rawValue: 7) returns actual instance of
UIView.AnimationCurve which crashes on access, mod by 4 limits value to max
*/
let animationCurve = UIView.AnimationCurve(rawValue: animationCurveInt % 4) ?? .easeIn
// View chanages
let topPoint = self.view.convert(keyboardFrameEnd.origin, from: self.view.window)
let height = self.view.bounds.size.height - topPoint.y
... update your constraints or manually update vars that affect layoutSubviews()...
let animationDuration: TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
var animationOptions: UIView.AnimationOptions = []
switch animationCurve {
case .easeInOut: animationOptions = .curveEaseInOut
case .easeIn: animationOptions = .curveEaseIn
case .easeOut: animationOptions = .curveEaseOut
case .linear: animationOptions = .curveLinear
}
// run animation
UIView.animate(withDuration: animationDuration, delay: 0, options: animationOptions, animations: {
self.view.layoutIfNeeded()
})
}
}