如何观察在SwiftUI macOS项目中使用NSNotification按下修饰符键(例如option, shift)



我想有一个Bool属性,表示按下@Publised var isOptionPressed = false的选项键。我会用它来改变SwiftUI视图

对此,我认为我应该使用Combine来观察键压

我试图为那个事件找到一个NSNotification,但对我来说似乎没有任何NSNotification,这可能对我有用。

好了,我找到了一个简单的解决方案:

class KeyPressedController: ObservableObject {
@Published var isOptionPressed = false

init() {
NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event -> NSEvent? in
if event.modifierFlags.contains(.option) {
self?.isOptionPressed = true
} else {
self?.isOptionPressed = false
}
return nil
}
}
}

既然你正在使用SwiftUI,我建议你在观察发布器之外再做一步,把修饰符标志的状态放在SwiftUIEnvironment中。我的观点是,它将很好地适应SwiftUI的声明性语法。

我有另一个实现,但采用了你找到的解决方案并调整了它。


import Cocoa
import SwiftUI
import Combine
struct KeyModifierFlags: EnvironmentKey {
static let defaultValue = NSEvent.ModifierFlags([])
}
extension EnvironmentValues {
var keyModifierFlags: NSEvent.ModifierFlags {
get { self[KeyModifierFlags.self] }
set { self[KeyModifierFlags.self] = newValue }
}
}
struct ModifierFlagEnvironment<Content>: View where Content:View {
@StateObject var flagState = ModifierFlags()
let content: Content;
init(@ViewBuilder content: () -> Content) {
self.content = content();
}
var body: some View {
content
.environment(.keyModifierFlags, flagState.modifierFlags)
}
}
final class ModifierFlags: ObservableObject {
@Published var modifierFlags = NSEvent.ModifierFlags([])
init() {
NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { [weak self] event in
self?.modifierFlags = event.modifierFlags
return event;
}
}
}

注意,我的事件闭包返回传入的事件。如果您返回nil,您将阻止事件进一步发展,并且系统中的其他人可能想要看到它。

结构体KeyModifierFlags建立一个要添加到视图Environment的新项。EnvironmentValues的扩展允许我们存储和从环境中检索当前标志。

最后是ModifierFlagEnvironment视图。它没有自己的内容——在@ViewBuilder函数中传递给初始化器。它所做的是提供包含状态监视器的StateObject,并将其修饰符标志的当前值传递给内容的Environment

要使用ModifierFlagEnvironment,您可以在层次结构中使用它包装顶级视图。在一个从默认Xcode模板构建的简单Cocoa应用中,我将应用的SwiftUI内容更改为:

struct KeyWatcherApp: App {
var body: some Scene {
WindowGroup {
ModifierFlagEnvironment {
ContentView()
}
}
}
}

因此应用程序中的所有视图都可以监视标志。

那么你可以这样使用它:

struct ContentView: View {
@Environment(.keyModifierFlags) var modifierFlags: NSEvent.ModifierFlags
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
if(modifierFlags.contains(.option)) {
Text("Option is pressed")
} else {
Text("Option is up")
}
}
.padding()
}
}

在这里,内容视图观察环境中的标志,并决定使用当前修饰符显示什么。

相关内容

  • 没有找到相关文章

最新更新