Вспомогательное представление ввода неожиданно ведет себя при скрытии и показе событий клавиатуры

Я сталкиваюсь со странным поведением с 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 наблюдается дважды:

  1. Когда клавиатура скрыта.
  2. Когда вид дополнительных устройств ввода скрыт (обратите внимание, что вид дополнительных устройств ввода отображается в течение некоторого времени после закрытия клавиатуры).

Если ваша реализация зависит от того, что селектор вызывается только один раз, вы можете использовать одно из следующих обходных путей:

Вариант 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)
}
Другие вопросы по тегам