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

UIResponder.keyboardWillShowNotification在曲面屏iOS设备上返回高度是否不准确?

解决曲面屏设备手动键盘避让高度偏大问题

我用UIResponder.keyboardWillShowNotification实现手动键盘避让,在iPhone SE这类方形屏设备上运行正常,但在iPhone 15 Pro Max这类曲面屏设备上,返回的键盘高度明显偏大。尝试结合容器底部安全区高度调整,但数值并不匹配。

问题代码

import SwiftUI

struct ContentView: View {
    @State private var text = ""
    
    @State private var keyboardHeight: CGFloat = .zero
    
    var body: some View {
        VStack {
            TextField("Test", text: $text)
            Color.red
                .frame(height: keyboardHeight)
        }
        .animation(.default.delay(0), value: keyboardHeight)
        .frame(maxHeight: .infinity, alignment: .bottom)
        .ignoresSafeArea(.keyboard)
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) {
            keyboardHeight = ($0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect).height
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
            keyboardHeight = .zero
        }
    }
}

效果对比

  • 曲面屏设备(异常):
    曲面屏异常效果
  • 方形屏设备(正常):
    方形屏正常效果

问题原因

UIResponder.keyboardFrameEndUserInfoKey返回的是键盘在全局屏幕坐标系中的高度,曲面屏设备(如iPhone 15 Pro Max)的屏幕底部包含灵动岛相关的系统预留区域,这部分区域不会被SwiftUI视图占用,但键盘高度计算时包含了这部分空间。直接使用该高度会导致视图上移过多,出现不必要的空白。

解决方案

通过GeometryReader获取当前视图的底部安全区高度,结合窗口安全区信息,从键盘全局高度中剔除系统不可用区域,计算出视图实际需要的避让高度。

修改后的代码:

import SwiftUI

struct ContentView: View {
    @State private var text = ""
    @State private var keyboardHeight: CGFloat = .zero
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                TextField("Test", text: $text)
                Color.red
                    .frame(height: keyboardHeight)
            }
            .animation(.default.delay(0), value: keyboardHeight)
            .frame(maxHeight: .infinity, alignment: .bottom)
            .ignoresSafeArea(.keyboard)
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
            guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
            guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                  let mainWindow = windowScene.windows.first else { return }
            
            // 剔除键盘高度中包含的屏幕底部系统预留区域
            let validKeyboardHeight = keyboardFrame.height - mainWindow.safeAreaInsets.bottom
            keyboardHeight = max(validKeyboardHeight, 0)
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
            keyboardHeight = .zero
        }
    }
}

关键说明

  1. 安全区适配:通过窗口安全区信息,剔除键盘高度中不属于视图交互区域的系统预留部分,确保避让高度精准匹配视图可用空间。
  2. 边界处理:用max(validKeyboardHeight, 0)避免出现负数高度,防止布局异常。

内容的提问来源于stack exchange,提问作者pinglock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:22:59