iOS为何仅显示inputAccessoryView未弹键盘时会触发keyboardWillShow通知
问题根因分析
1. 无键盘弹出时触发keyboardWillShow通知的原因
你重写了当前视图控制器的canBecomeFirstResponder返回true,视图控制器加载后会自动成为第一响应者。系统为了加载并展示控制器绑定的inputAccessoryView,会主动派发UIResponder.keyboardWillShowNotification通知,此时通知携带的keyboardFrameEndUserInfoKey对应的高度等于你的chatBoxView高度,并非真实系统键盘的高度,所以会出现你看到的“没弹键盘也触发通知”的现象。
2. 收起键盘后再次触发keyboardWillShow通知的原因
当你点击空白处收起键盘时,当前第一响应者是chatBoxView内部的growingTextView,调用endEditing后growingTextView会resign第一响应者。此时系统检测到当前页面的视图控制器canBecomeFirstResponder返回true,会自动将控制器重新置为第一响应者,再次触发加载inputAccessoryView的流程,因此会先走keyboardWillHide,之后立刻触发keyboardWillShow。
修复方案
- 先在
keyboardWillShow方法中增加高度过滤逻辑,排除仅加载inputAccessoryView的场景:
@objc func keyboardWillShow(notification: Notification) { guard let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height else { return } // 真实键盘弹出时高度必然大于inputAccessoryView高度,过滤无效通知 guard keyboardHeight > chatBoxView.frame.height else { return } print("Notification: Keyboard will show") DispatchQueue.main.async { self.tableView.setBottomInset(to: keyboardHeight - self.chatBoxView.frame.height) self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true) } }
- 如果不需要常驻显示输入框,可以调整实现逻辑:将
chatBoxView作为普通子视图钉在页面底部,仅在growingTextView成为第一响应者时,将其设置为growingTextView的inputAccessoryView,彻底避免控制器作为第一响应者带来的多余通知。 - 如果需要保留现有常驻输入框的实现,可在
growingTextView结束编辑时,主动调用控制器的resignFirstResponder(),避免控制器自动成为第一响应者触发重复通知。
内容的提问来源于stack exchange,提问作者infiniteObj
相关产品推荐
相关产品推荐

