焦点对象随着用户交互而变为零

问题描述 投票:0回答:1

我有一个多窗口应用程序,因此我使用

focusedSceneObject
将交互定向到当前窗口。然后,我在视图中看到一个
@FocusedObject
,这在视图出现时似乎是正确的。但是,视图需要查看键盘事件,因此我有一个视图利用
NSViewRepresentable
提供一种访问 SwiftUI 中的事件的方法。问题是当视图响应事件时,
@FocusedObject
变量为零。

这是

NSViewRepresentable
视图:

import SwiftUI

struct KeyAwareView: NSViewRepresentable {
    let onEvent: (NSEvent) -> Void

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

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

private class KeyView: NSView {
    var onEvent: (NSEvent) -> Void = { _ in }
    
    override var acceptsFirstResponder: Bool { true }
    override func keyDown(with event: NSEvent) {
        onEvent(event)
    }
    override func keyUp(with event: NSEvent) {
        onEvent(event)
    }
    override func flagsChanged(with event: NSEvent) {
        onEvent(event)
    }
}

该应用程序具有此类代码(为了清楚起见,删除了一些细节):

extension FocusedValues {
    struct DocumentFocusedValues: FocusedValueKey {
        typealias Value = MyDocument
    }

    var document: MyDocument? {
        get { self[DocumentFocusedValues.self] }
        set { self[DocumentFocusedValues.self] = newValue }
    }
}

@main
struct MyApp: App {
    var body: some Scene {
        DocumentGroup {
            MyDocument()
        } editor: { file in
            DocumentView(document: file.document)
                .focusedSceneObject(file.document as MyDocument)
        }
    }
}

视图的简化版本:

struct DocumentView: View {
    @FocusedObject var focusedDocument: MyDocument?
    
    var body: some View {
        ZStack {
            NavigationSplitView {
                // The list view
            }
            detail: {
                // The detail view
            }
            .focusable()

            KeyAwareView { event in
                switch event.type {
                case .keyDown:
                    let notification = Notification(name: .keyDown, object: focusedDocument, userInfo: [KeyKeyCode: Int(event.keyCode)])
                    NotificationCenter.default.post(name: .keyboardEvent, object: focusedDocument, userInfo: [KeyNotification: notification])
                    
                case .keyUp:
                    // Code for key up event
                    
                case .flagsChanged:
                    // Code for modifiers changed event
                    
                default:
                    break
                }
            }
        }
    }
}

当我遇到

keyDown
的情况时,
focusedDocument
为零。我做错了什么? (顺便说一句,我尝试过删除
.focusable()
语句,或将其附加到层次结构的不同部分,但这没有什么区别。)

macos swiftui
1个回答
0
投票

问题是被调用的块可以访问上下文,但是

@FocusedObject
没有在那里设置,因此工作必须在视图结构内完成。

执行此操作的一种简单方法是在

KeyAwareView
变量的
NSEvent?
中创建绑定,然后修改视图以添加将事件传递给绑定变量的协调器。然后工作在文档视图的
onChangeOf
修饰符中完成。

这是新版本的

KeyAwareView

protocol KeyEventHandler {
    func handleEvent(event: NSEvent)
}

struct KeyAwareView: NSViewRepresentable {
    class Coordinator: NSObject, KeyEventHandler {
        var parent: KeyAwareView
        
        init(_ parent: KeyAwareView) {
            self.parent = parent
        }
        
        func handleEvent(event: NSEvent) {
            parent.event = event
        }
    }
    
    @Binding var event: NSEvent?

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

    func updateNSView(_ nsView: NSView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
}

private class KeyView: NSView {
    var handler: KeyEventHandler?
    
    override var acceptsFirstResponder: Bool { true }
    override func keyDown(with event: NSEvent) {
        handler?.handleEvent(event: event)
    }
    override func keyUp(with event: NSEvent) {
        handler?.handleEvent(event: event)
    }
    override func flagsChanged(with event: NSEvent) {
        handler?.handleEvent(event: event)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.