You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在任意时刻获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:31:41