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

时间:2020-05-16 06:17:53

标签: swift macos uikit swiftui

我正在使用SwiftUI制作macOS应用程序。我有一个符合NSViewRepresentable的结构,其目的是检测所按下的键的键代码。我想将event.keyCode传递回SwiftUI并将其保存到环境对象中,以便可以在应用程序的其他位置使用键代码。
我知道我应该使用SwiftUI协调器,但是我可以找到的所有教程和堆栈溢出问题都使用具有预先配置的委托的现成类,例如UIPageControlUISearchBar。我不确定使用简单的自定义NSView时该怎么做。有人可以解释使用自定义NSViewRepresentable时如何将数据从@EnvironmentObject结构传递到我的NSView吗?

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控制台,因此检测正常。

1 个答案:

答案 0 :(得分:4)

这是一个解决方案(包含一些重复的部分)。经过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 !!!
        }
    }
}