如何在存在自定义输入辅助视图时独立检测原生键盘高度?
解决自定义输入辅助视图下原生键盘高度的解耦方案
嘿,这个问题我之前在做带自定义输入辅助视图的键盘适配时也踩过坑,硬编码辅助视图高度不仅维护麻烦,还容易在不同设备/系统版本出问题,分享几个我亲测好用的解耦方案:
方案1:通过当前第一响应者动态获取辅助视图高度
核心思路是:当键盘弹出时,找到当前的第一响应者(比如UITextField/UITextView),直接获取它绑定的自定义输入辅助视图的高度,再从通知返回的总高度中减去,得到原生键盘高度。
首先需要实现一个获取当前第一响应者的扩展:
extension UIResponder { static func currentFirstResponder() -> UIResponder? { _currentFirstResponder = nil UIApplication.shared.sendAction(#selector(findFirstResponder(_:)), to: nil, from: nil, for: nil) return _currentFirstResponder } private static weak var _currentFirstResponder: UIResponder? @objc private func findFirstResponder(_ sender: Any) { UIResponder._currentFirstResponder = self } }
然后修改你的键盘通知回调:
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { [weak self] notification in guard let userInfo = notification.userInfo, let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect, let firstResponder = UIResponder.currentFirstResponder() as? UIView, let accessoryHeight = firstResponder.inputAccessoryView?.bounds.height else { return } // 计算得到原生键盘的真实高度 let nativeKeyboardHeight = keyboardFrame.size.height - accessoryHeight // 这里写你的高度适配逻辑 }
这个方案不需要硬编码任何高度值,完全依赖系统视图的实际尺寸,兼容性很好。
方案2:利用UIKeyboardLayoutGuide(iOS 11+)
iOS 11之后苹果引入了UIKeyboardLayoutGuide,这个布局指南的高度就是原生键盘的纯高度(不包含自定义输入辅助视图),直接用它就能跳过计算步骤,非常省心。
在你的ViewController中可以这样用:
override func viewDidLoad() { super.viewDidLoad() // 绑定布局约束(示例:让某个视图贴在键盘顶部) NSLayoutConstraint.activate([ yourCustomView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor) ]) // 如果需要主动获取高度,可以监听布局指南的frame变化 NotificationCenter.default.addObserver(forName: NSNotification.Name.UILayoutGuideFrameDidChange, object: view.keyboardLayoutGuide, queue: .main) { [weak self] _ in let nativeKeyboardHeight = self?.view.keyboardLayoutGuide.layoutFrame.height ?? 0 // 处理高度逻辑 } }
这个方案是苹果官方推荐的,代码最简洁,没有计算成本,唯一限制是需要支持iOS 11及以上版本。
方案3:预加载原生键盘高度(兼容旧版本)
如果需要兼容iOS 10及以下,可以用一个小技巧:临时创建一个不带输入辅助视图的输入框,触发键盘弹出,记录原生键盘高度后再收起。
private var cachedNativeKeyboardHeight: CGFloat = 0 func preloadNativeKeyboardHeight() { // 创建临时输入框,放在屏幕外避免视觉干扰 let tempTextField = UITextField(frame: CGRect(x: -1000, y: -1000, width: 0, height: 0)) tempTextField.inputAccessoryView = nil // 确保没有附加辅助视图 view.addSubview(tempTextField) // 监听键盘弹出通知 let observer = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { [weak self, weak tempTextField] notification in guard let userInfo = notification.userInfo, let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return } // 缓存原生键盘高度 self?.cachedNativeKeyboardHeight = keyboardFrame.size.height // 收起键盘并移除临时视图 tempTextField?.resignFirstResponder() tempTextField?.removeFromSuperview() // 移除临时观察者 NotificationCenter.default.removeObserver(observer) } // 触发键盘弹出 tempTextField.becomeFirstResponder() }
可以在App启动或ViewController初始化时调用这个方法预加载,之后直接用缓存的高度即可。缺点是会有一次短暂的键盘弹出(但因为视图在屏幕外,用户看不到),适合旧版本兼容场景。
内容的提问来源于stack exchange,提问作者Milan Nosáľ
相关产品推荐
相关产品推荐

