将数据从简单的NSView传递到SwiftUI视图

5
我正在使用SwiftUI开发macOS应用程序。我有一个遵循NSViewRepresentable的结构体,其目的是检测按下的任何键的键码。我想将event.keyCode传递回SwiftUI并将其保存到环境对象中,以便在应用程序的其他位置使用该键码。
我知道应该使用SwiftUI协调器,但我能找到的所有教程和Stack Overflow问题都使用预先配置了代理的现成类,例如UIPageControlUISearchBar。当使用简单的自定义NSView时,我不确定该怎么做。有人能解释一下如何在使用自定义NSView时将数据从NSViewRepresentable结构传递到我的@EnvironmentObject中吗?
struct KeyboardEvent: NSViewRepresentable {

    class KeyView: NSView {
        override var acceptsFirstResponder: Bool { true }
        override func keyDown(with event: NSEvent) {
            print("\(event.keyCode)")
        }
    }

    func makeNSView(context: Context) -> NSView {
        let view = KeyView()
        DispatchQueue.main.async {
            view.window?.makeFirstResponder(view)
        }
        return view
    }

    func updateNSView(_ nsView: NSView, context: Context) {
    }

}

struct ContentView: View {
    @EnvironmentObject var input: KeyboardInput     // save the keyCode here
    var body: some View {
        VStack {
            Text(input.keyCode)
            KeyboardEvent()
        }
    }
}

现在它通常将键码打印到Xcode控制台,所以检测工作正常。


顺便说一句,我知道这个问题非常简单,但我对应用程序开发非常新手,而且我已经卡在这里好几天了,所以任何帮助都将不胜感激! - andrewhoff
1个回答

6

以下是一个解决方案(一些部分是复制的)。已测试使用 Xcode 11.4 / macOS 10.15.4。

class KeyboardInput: ObservableObject {
    @Published var keyCode: UInt16 = 0
}

struct KeyboardEvent: NSViewRepresentable {
    @Binding var keyStorage: UInt16          // << here !!
    init(into storage: Binding<UInt16>) {
        _keyStorage = storage
    }

    class KeyView: NSView {
        var owner: KeyboardEvent?   // << view holder

        override var acceptsFirstResponder: Bool { true }
        override func keyDown(with event: NSEvent) {
            print("\(event.keyCode)")
            owner?.keyStorage = event.keyCode
        }
    }

    func makeNSView(context: Context) -> NSView {
        let view = KeyView()
        view.owner = self           // << inject
        DispatchQueue.main.async {
            view.window?.makeFirstResponder(view)
        }
        return view
    }

    func updateNSView(_ nsView: NSView, context: Context) {
    }

}

struct ContentView: View {
    @EnvironmentObject var input: KeyboardInput     // save the keyCode here
    var body: some View {
        VStack {
            Text("Code: \(input.keyCode)")
            KeyboardEvent(into: $input.keyCode) // << binding !!!
        }
    }
}

我将这段代码复制到项目中后,出现了以下错误:SwiftUI/EnvironmentObject.swift:70: 致命错误:未找到类型为KeyboardInput的ObservableObject。可能缺少一个View.environmentObject(_:),作为此视图的祖先。 - boxed
嘿,朋友,没必要这么粗鲁。只是想让你知道答案可能不正确、不完整或者有些变化了。也许在新版本的Xcode中甚至存在着一个bug... - boxed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接