输入附件视图行为异常与键盘隐藏和显示事件
Posted
技术标签:
【中文标题】输入附件视图行为异常与键盘隐藏和显示事件【英文标题】:Input Accessory View Behave Unexpectedly with keyboard hide and show events 【发布时间】:2018-07-16 06:05:22 【问题描述】:我在使用 InputAccessoryView 时遇到了一个奇怪的行为,我正在使用 InputAccessoryView
的聊天屏幕上工作,我已经注册了 KeyboardWillShow
和 KeyboardWillHide
通知。当我的聊天屏幕出现时,它会自动调用一次KeyboardWillShowMethod
,之后它会自动隐藏而不调用KeyboardWillHide
通知。加载聊天后,当我单击文本框输入文本时,它调用KeyboardWillShow
,这很好。但是当我尝试隐藏键盘时,它首先调用两个方法,它会调用KeyboardWillHide
,然后它会调用KeyboardWillShow
,这很奇怪。
这是我隐藏键盘时的聊天屏幕Image。 这是显示键盘的时候Image
我正在以编程方式使用此InputAccessoryView
代码inputAccessoryView
这就是我注册键盘通知的方式。
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
)
在选择器中,我试图根据键盘的 Y 索引更改我的 CollectionView
插入,因为我没有得到键盘的高度,这也是一个问题。键盘高度始终为 inputAccessoryView 高度的 50。
【问题讨论】:
显示您的选择器代码。 @RakeshaShastri 我已经用选择器方法更新了问题。 试试UIKeyboardFrameBeginUserInfoKey
,而不是UIKeyboardFrameEndUserInfoKey
。
如果它对您的场景有帮助,也请检查:***.com/questions/47286239/…。
嘿@Amit 谢谢。它有很大帮助。
【参考方案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
)
【讨论】:
【参考方案2】:当键盘有输入附件视图时,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)
【讨论】:
以上是关于输入附件视图行为异常与键盘隐藏和显示事件的主要内容,如果未能解决你的问题,请参考以下文章
iOS 7 – 隐藏的输入附件视图显示在 bannerViewActionShouldBegin:willLeaveApplication: 之后