SwiftUI iOS - 如何捕获硬件按键事件

Jes*_*sen 5 uikeycommand swiftui

我是 iOS 开发的新手。按照教程,我使用 SwiftUI 创建了一个简单的计算器。

我的 iPad 上有一个键盘,我希望能够使用键盘输入值。

如何在 SwiftUI 应用程序(没有文本字段)中捕获和处理硬件键盘事件?我尝试在 SceneDelegate (UIResponder) 上使用 keyCommands,如下所示,但这对我不起作用。只要我按下 iPad 上的任意键,我就会在 XCode 跟踪视图中看到“与守护进程的连接已失效”。

 class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    override var canBecomeFirstResponder: Bool {
        return true;
    }
    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "a", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
        ]
    }

    @objc func test(_ sender: UIKeyCommand) {
        print("test was pressed")
    }
Run Code Online (Sandbox Code Playgroud)

谢谢

Asp*_*eri 7

它需要覆盖托管视图控制器,并且一切正常。使用 Xcode 11.2 / iOS 13.2 测试

这是示例代码

class KeyTestController<Content>: UIHostingController<Content> where Content: View {

    override func becomeFirstResponder() -> Bool {
        true
    }

    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "1", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: "0", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
        ]
    }

    @objc func test(_ sender: UIKeyCommand) {
        print(">>> test was pressed")
    }

}
Run Code Online (Sandbox Code Playgroud)

SceneDelegate下面的某个地方

window.rootViewController = KeyTestController(rootView: contentView)
Run Code Online (Sandbox Code Playgroud)


tyi*_*ine 5

如果您使用的是 SwiftUI 生命周期,@Asperi 还展示了如何rootViewController在这篇文章中访问 -使用 iOS 14 @main 时托管控制器

\n

总之,HostingWindowFinder追踪 的可变版本rootViewController并提供对其的访问。

\n
struct ContentView: View {\n\n    var body: some View {\n      Text("Demo Root Controller access")\n        .withHostingWindow { window in\n            window?.rootViewController = KeyController(rootView: ContentView())\n        }\n    }\n}\n\nextension View {\n    func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View {\n        self.background(HostingWindowFinder(callback: callback))\n    }\n}\n\nstruct HostingWindowFinder: UIViewRepresentable {\n    var callback: (UIWindow?) -> ()\n\n    func makeUIView(context: Context) -> UIView {\n        let view = UIView()\n        DispatchQueue.main.async { [weak view] in\n            self.callback(view?.window)\n        }\n        return view\n    }\n\n    func updateUIView(_ uiView: UIView, context: Context) {\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\n

如果您只想监控原始键盘输入使用pressesBegan(...)- WWDC 2019 Talk

\n
class KeyController<Content>: UIHostingController<Content> where Content: View {\n\n    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {\n        for press in presses {\n            guard let key = press.key else { continue }\n            print(key)\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

非常感谢@Asperi!\xe2\x9d\xa4\xef\xb8\x8f

\n