Input Accessory View Behave Unexpectedly with keyboard hide and show events

时光总嘲笑我的痴心妄想 提交于 2019-12-24 01:38:10

问题


I am facing an strange behavior with InputAccessoryView, I am working on chat screen where I have used InputAccessoryView where I have registered for KeyboardWillShow and KeyboardWillHide notifications. When my chat screen appears it automatically calls the KeyboardWillShowMethod once and after that it hides automatically without calling the KeyboardWillHide notification. After Loading chats when I click on textbox to type text it calls KeyboardWillShow which is fine. But when I try to hide keybaord it calls two methods first it will call KeyboardWillHide and after that it will call KeyboardWillShow which is strange.

This is my chat screen Image when keyboard is hidden. This is when keyboard is shown Image

I am using this InputAccessoryView Code Programatically inputAccessoryView

This is how I have registered for keyboard notifications.

  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

            })
        }
    }

In selectors I am trying to change my CollectionView Insets according to a Y Index of Keyboard because I am not getting Height of keybaord that is also an issue. Height of kyeboard is always 50 as of height of inputAccessoryView.


回答1:


Here is the solution which I have found Thanx to @Amit. Instead of using UIKeyboardFrameBeginUserInfoKey I have used UIKeyboardFrameEndUserInfoKey after doing this I was able to get accurate hight of keyboard in KeyboardWillAppear method. Now the problem which remains was that KeyboardWillShow method was get called after KeyboardWillHide but at that time the KeyboardWillShow have a hight of keyboard 50. That means when i try to hide a keyboard it will call KeyboardWillHide which is fine and after that It automatically calls KeyboardWillShow but height of keyboard remains 50 so I put condition there.

Now following method will make effect only when height is more than 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

            })
        }
    }



回答2:


When keyboard has input accessory view, keyboardDidHideNotification is observed twice:

  1. When keyboard is hidden.
  2. When input accessroy view is hidden (note that input accessory view is visible for a while after keyboard is dismissed).

If your implementation depends on selector to be called just once, you can do one of following workarounds:

Option A: Check keyboard frame:

@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
    }
}

Option B: Throttle reaction using 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)
}


来源:https://stackoverflow.com/questions/51355483/input-accessory-view-behave-unexpectedly-with-keyboard-hide-and-show-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!