这个包提供了一种方式,可以将来自 key
窗口的值共享到应用程序的所有其他部分。(macOS/iPadOS 中的 key
窗口是当前响应键盘快捷键的窗口)。
此包的主要用例是使能够将来自 key
窗口的值传递到 SwiftUI 生命周期应用程序的 commands
部分中的视图。
import KeyWindow
@main
struct ExampleWindowReaderApp: App {
var body: some Scene {
WindowGroup {
ContentView().observeWindow()
}.commands {
CommandMenu("MyMenue") {
MenuButton()
}
}
}
}
注意: 重要的是使用 .observeWindow()
修饰符包裹你的应用程序的 ContentView
,这使得 KeyWindow
能够观察这个窗口及其发布的值。
在我们的 ContentView
及其子视图中,我们可以像发布 Preferences 一样发布值。
首先,创建一个符合 KeyWindowValueKey
协议的结构体,并声明值的类型。
struct SelectedProjectWindowValueKey: KeyWindowValueKey {
typealias Value = Binding<UUID>
}
struct SelectedProjectTitleWindowValueKey: KeyWindowValueKey {
typealias Value = String
}
然后,为了在我们的视图中提供这些值,我们可以使用 .keyWindow(SelectedProjectWindowValueKey.self, $projectSelection)
来设置它们。 这将向上冒泡,当窗口变为 key
时,我们可以在我们的 MenuButton
中读取这些值。
struct MenuButton: View {
@KeyWindowValue(SelectedProjectTitleWindowValueKey.self)
var title: String
@KeyWindowValueBinding(SelectedProjectWindowValueKey.self)
var selectedProject: UUID?
var body: some View {
Button(action: {
// Delete the selectedProject
self.selectedProject = // some other project
}, label: {
Text("Delete \(title)")
})
}
}
注意: 你不能在 struct MyCommands: Commands
类型中使用 @KeyWindowValue
或 @KeyWindowValueBinding
。 你需要将 Buttons
从 Commands
的 body 中提取到它们自己的 Views 中,以便你可以使用这些属性包装器(这是 SwiftUI 的一个限制)。
有关共享来自 key 窗口的文档以便在 commands 部分中访问的更详细信息,请参阅 这篇博客文章,其中涵盖了此用例。
你也可以在其他视图中使用 @KeyWindowValue
和 @KeyWindowValueBinding
,但要小心确保它们不会导致 .keyWindow
修饰符被重复调用,否则可能会陷入循环。 最佳方法是在你的视图层次结构中设置所有 .keyWindow
,仅在深度嵌套的子视图上使用 @KeyWindowValue
和 @KeyWindowValueBinding
。
此外,此包还提供了可以读取的 EnvironmentValues.isKeyWindow
,以检测视图是否在 key
窗口中。(你可以使用它来更改渲染样式)。 请注意,这与 scenePhase
不同,scenePhase
指示场景是否 active
,而不是视图的窗口是否在 Key Window 中。 在 iPadOS 和 macOS 上,你可以有多个场景处于活动状态,并且在 macOS 上,每个场景可以有多个窗口,但任何给定时间只有一个窗口是 key 窗口。
根据你尝试从 key 窗口共享的数据类型,你可以使用几种不同的属性包装器来读取该值
类型 | 属性包装器 | 注释 |
---|---|---|
"String" , 42 或者 MyStruct |
@KeyWindowValue |
出于性能原因,最好是这些值类型符合 equatable 协议 |
Binding<MyStruct> |
@KeyWindowValueBinding |
- |
Binding<Optional<MyStruct>> |
@KeyWindowOptionalValueBinding |
- |
Observable 对象 |
@KeyWindowObservableObject |
在这种情况下,Key 需要符合 KeyWindowObservableObjectKey 协议并提供 defaultValue |