如何在任意时刻获取UIKeyboardFrame高度?解决控制器切换场景难题
解决控制器切换时获取已显示键盘高度的思路
我之前也碰到过一模一样的问题,苹果官方确实没提供直接查询键盘当前状态的API,但有几个靠谱的方案能解决这个需求:
1. 全局维护键盘状态(最推荐,无私有API依赖)
你可以做一个全局的键盘状态管理类,或者在基类ViewController里维护,每次通过系统通知更新当前键盘高度,这样任何控制器都能直接读取这个值:
// 全局键盘管理类示例 class KeyboardStateManager { static let shared = KeyboardStateManager() private(set) var currentKeyboardHeight: CGFloat = 0 private init() { setupNotificationListeners() } private func setupNotificationListeners() { let center = NotificationCenter.default center.addObserver(self, selector: #selector(handleKeyboardShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) center.addObserver(self, selector: #selector(handleKeyboardHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } @objc private func handleKeyboardShow(_ notification: Notification) { guard let userInfo = notification.userInfo, let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } currentKeyboardHeight = keyboardFrame.height } @objc private func handleKeyboardHide(_ notification: Notification) { currentKeyboardHeight = 0 } }
然后在你的控制器的viewDidAppear里直接读取这个值,触发约束更新:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let keyboardHeight = KeyboardStateManager.shared.currentKeyboardHeight if keyboardHeight > 0 { updateConstraintsForKeyboard(height: keyboardHeight) } }
这个方法完全基于官方通知,没有任何私有API风险,稳定性最高,我自己项目里一直用这种方式。
2. 直接遍历系统窗口获取键盘视图Frame
键盘本质是系统keyWindow的子视图,我们可以遍历窗口子视图找到键盘,读取它的高度:
private func getCurrentKeyboardHeight() -> CGFloat { guard let keyWindow = UIApplication.shared.connectedScenes .filter({ $0.activationState == .foregroundActive }) .compactMap({ $0 as? UIWindowScene }) .first?.windows .first(where: { $0.isKeyWindow }) else { return 0 } for subview in keyWindow.subviews { // 匹配键盘相关视图的描述(不同iOS版本类名略有差异) let viewDesc = subview.description if viewDesc.contains("UIKeyboard") || viewDesc.contains("UIRemoteKeyboardView") { // 转换到当前控制器视图的坐标系 let frameInView = keyWindow.convert(subview.bounds, to: self.view) return frameInView.height } } return 0 }
同样在viewDidAppear里调用这个方法,如果返回高度大于0,就更新约束。这种方法不需要全局状态,但依赖键盘视图的描述字符串,虽然在iOS10到iOS17测试都稳定,但毕竟是未公开的细节,有极小的版本适配风险。
3. 利用安全区域内边距(仅适用于全屏无底部栏场景)
如果你的控制器是全屏显示(没有TabBar或底部导航栏),当键盘弹出时,keyWindow的safeAreaInsets.bottom会等于键盘高度,你可以直接读取:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) guard let keyWindow = UIApplication.shared.keyWindow else { return } let keyboardHeight = keyWindow.safeAreaInsets.bottom // 排除状态栏高度的干扰 if keyboardHeight > keyWindow.safeAreaInsets.top { updateConstraintsForKeyboard(height: keyboardHeight) } }
这个方法最简洁,但局限性很大——如果有底部栏,safeAreaInsets.bottom会包含栏的高度,无法直接得到纯键盘高度。
内容的提问来源于stack exchange,提问作者root
相关产品推荐
相关产品推荐

