Вспомогательное представление ввода неожиданно ведет себя при скрытии и показе событий клавиатуры
Я сталкиваюсь со странным поведением с InputAccessoryView, я работаю на экране чата, где я использовал InputAccessoryView
где я зарегистрировался KeyboardWillShow
а также KeyboardWillHide
уведомления. Когда появляется мой экран чата, он автоматически вызывает KeyboardWillShowMethod
один раз и после этого автоматически скрывается без вызова KeyboardWillHide
уведомление. После загрузки чатов, когда я нажимаю на текстовое поле, чтобы набрать текст, он вызывает KeyboardWillShow
что хорошо Но когда я пытаюсь скрыть keybaord, сначала он вызывает два метода KeyboardWillHide
и после этого он позвонит KeyboardWillShow
что странно
Это изображение моего чата, когда клавиатура скрыта. Это когда клавиатура отображается изображение
Я использую это InputAccessoryView
Код программно ввода AccessoryView
Вот как я зарегистрировался для уведомлений клавиатуры.
func handleKeyBoard(){
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
var contentInset = self.collectionView?.contentInset
contentInset?.bottom = keyboardSize.maxY
self.collectionView?.contentInset = contentInset!
self.collectionView?.scrollIndicatorInsets = contentInset!
// collectionViewBottomAnchor?.constant = keyboardSize.height + 50
// print ("input height \(inputAccessoryView?.frame.maxY) ")
// print("keyboard height \(keyboardSize.height)")
// print("keyboard Y \(keyboardSize.maxY)")
// print("keyboard Y \(keyboardSize.minY)")
//print("keyboard Y \(inputAccessoryView.framemaxY)")
if self.messages.count > 0{
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completed:Bool) in
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
})
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("keyboard hide")
self.collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
self.collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completed:Bool) in
})
}
}
В селекторах я пытаюсь изменить свой CollectionView
Вставки в соответствии с индексом Y клавиатуры, потому что я не получаю высоту клавиатуры, что также является проблемой. Высота клавиатуры всегда равна 50 от высоты inputAccessoryView.
1 ответ
Вот решение, которое я нашел благодаря @Amit. Вместо того, чтобы использовать UIKeyboardFrameBeginUserInfoKey
я использовал UIKeyboardFrameEndUserInfoKey
после этого я смог получить точную высоту клавиатуры в KeyboardWillAppear
метод. Теперь проблема, которая остается KeyboardWillShow
метод был вызван после KeyboardWillHide
но в то время KeyboardWillShow
иметь высоту клавиатуры 50. Это означает, что когда я пытаюсь скрыть клавиатуру, она будет вызывать KeyboardWillHide, что хорошо, и после этого он автоматически вызывает KeyboardWillShow
но высота клавиатуры остается 50, поэтому я поставил условие там.
Теперь следующий метод будет действовать только тогда, когда высота больше 50.
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if keyboardSize.height > 50{
var contentInset = self.collectionView?.contentInset
contentInset?.bottom = keyboardSize.height + 50
self.collectionView?.contentInset = contentInset!
self.collectionView?.scrollIndicatorInsets = contentInset!
if self.messages.count > 0{
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completed:Bool) in
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
})
}
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.collectionView?.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 52, right: 0)
self.collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 52, right: 0)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (completed:Bool) in
})
}
}
Когда клавиатура имеет вид аксессуаров ввода, keyboardDidHideNotification
наблюдается дважды:
- Когда клавиатура скрыта.
- Когда вид дополнительных устройств ввода скрыт (обратите внимание, что вид дополнительных устройств ввода отображается в течение некоторого времени после закрытия клавиатуры).
Если ваша реализация зависит от того, что селектор вызывается только один раз, вы можете использовать одно из следующих обходных путей:
Вариант A. Проверьте рамку клавиатуры:
@objc
private func keyboardDidHide(_ notification: Notification) {
guard let keyboardRect = notification.keyboardRect, keyboardRect.origin.y == view.frame.maxY else {
return
}
// Do whatever you need...
}
extension Notification {
var keyboardRect: CGRect? {
guard let keyboardSize = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
return nil
}
return keyboardSize.cgRectValue
}
}
Вариант B: Дросселирование с помощью GDC:
private var pendingKeyboardDidHideRequestWorkItem: DispatchWorkItem?
private func keyboardDidHide(_ notification: Notification) {
pendingKeyboardDidHideRequestWorkItem?.cancel()
let keyboardDidHideRequestWorkItem = DispatchWorkItem { [weak self] in
// Do whatever you need...
}
pendingKeyboardDidHideRequestWorkItem = keyboardDidHideRequestWorkItem
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute: keyboardDidHideRequestWorkItem)
}