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

iOS 18中Swift的pressesBegan方法失效?如何恢复捕获?

iOS 18 中重新捕获 pressesBegan 事件的解决方案

你的代码在 iOS 17 正常但 iOS 18 失效,主要是因为 iOS 18 对 UIView 的事件处理逻辑、第一响应者状态要求更严格,同时无尺寸视图的事件捕获规则有变化。以下是两种可行的修复方案:

方案一:适配原有 UIViewRepresentable 实现

修改代码,确保视图拥有可交互区域并成为第一响应者:

struct ContentView: View {
    var body: some View {
        KeyBoardView()
            .frame(maxWidth: .infinity, maxHeight: .infinity) // 让视图占满整个父容器,获得交互区域
    }
}

struct KeyBoardView: UIViewRepresentable{
    func makeUIView(context: Context) -> KeyEventView {
        KeyEventView()
    }

    func updateUIView(_ uiView: KeyEventView, context: Context) {}

    class KeyEventView: UIView {
        // 允许视图成为第一响应者
        override var canBecomeFirstResponder: Bool { true }
        
        init() {
            super.init(frame: .zero)
            translatesAutoresizingMaskIntoConstraints = false
            isUserInteractionEnabled = true // 明确开启用户交互
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        // 视图添加到窗口时,主动成为第一响应者
        override func didMoveToWindow() {
            super.didMoveToWindow()
            becomeFirstResponder()
        }
        
        override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
            super.pressesBegan(presses, with: event) // 保留事件传递链
            print("test - pressesBegan triggered")
        }
    }
}

关键修改点:

  • 给 KeyBoardView 添加 .frame(maxWidth: .infinity, maxHeight: .infinity),解决原视图无尺寸无法接收事件的问题
  • 重写 canBecomeFirstResponder 返回 true,并在 didMoveToWindow 中调用 becomeFirstResponder(),确保视图获得第一响应者身份(iOS 18 部分键盘事件需要此状态)
  • 添加 super.pressesBegan(presses, with: event),保证事件响应链正常传递,避免系统拦截事件

方案二:改用 SwiftUI 原生 API(推荐)

iOS 17+ 提供了 SwiftUI 原生的按键事件处理修饰符 onKeyPress,无需依赖 UIKit 包装,更符合 SwiftUI 开发风格,iOS 18 中可正常工作:

struct ContentView: View {
    var body: some View {
        Color.clear
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .onKeyPress(.any) { press in
                print("test - 按键触发: \(press.key)")
                // 返回 .handled 表示消费事件,返回 .forward 表示继续传递事件
                return .handled
            }
    }
}

这个方案无需编写 UIViewRepresentable 代码,实现更简洁,同时能捕获所有按键事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:12:43