我有一个 macOS 应用程序,当用户按下菜单项“信息”时,它必须显示一个包含一些信息的小对话框。
我尝试使用
.sheet
调用此操作,但无法让它显示工作表。代码:
@main
struct The_ThingApp: App {
private let dataModel = DataModel()
@State var showsAlert = false
@State private var isShowingSheet = false
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.dataModel)
}
.commands {
CommandMenu("Info") {
Button("Get Info") {
print("getting info")
isShowingSheet.toggle()
}
.sheet(isPresented: $isShowingSheet) {
VStack {
Text("Some stuff to be shown")
.font(.title)
.padding(50)
Button("Dismiss",
action: { isShowingSheet.toggle() })
}
}
}
}
}
}
如何显示菜单项中的工作表?
但是,如果表格不是实现这一点的方法(我认为考虑到我需要展示的内容的简单性,那就是它),您建议我如何做?我尝试创建一个新视图,就像我在首选项窗口中所做的那样,但我也无法从菜单中调用它。
这个答案有点晚了,但希望能提供一些与多窗口应用程序配合良好的指导。观看完 WWDC20 中的 Mac 上的 SwiftUI:构建基础知识 并查看 针对 focusSceneValue 的 Apple 开发人员文档,在尊重多个窗口的同时显示工作表的最佳方式是使用
focusedSceneValue
。
如果您有很多内容依赖于所选/聚焦的
Scene
,您可以使用 @FocusedObject
代替,类似于使用 @EnvironmentObject
。
设置一个键,在按钮中使用
@FocusedValue
时显示在选项列表中:
struct ShowSheetKey: FocusedValueKey {
typealias Value = Binding<Bool>
}
extension FocusedValues {
var showSheet: Binding<Bool>? {
get { self[ShowSheetKey.self] }
set { self[ShowSheetKey.self] = newValue }
}
}
在
ContentView
创建状态来控制工作表的演示并使用 .focusedSceneValue
修饰符链接它:
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Text("Hello, world!")
// This will make an instance of the showSheet binding outside of the view, to any view that peels it out via @FocusedValue (similar to using @Environment)
.focusedSceneValue(\.showSheet, $showSheet)
.sheet(isPresented: $showSheet) {
Text("I'm in a sheet!")
}
}
}
创建一个可用于创建菜单命令的按钮。
struct ShowSheetButton: View {
@FocusedValue(\.showSheet) private var showSheet
var body: some View {
Button {
showSheet?.wrappedValue = true
} label: {
Label("Show Sheet", systemImage: "eye")
}
.disabled(showSheet == nil)
}
}
最后,在
commands
的 Scene
中更新您的 App
修改器。
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
CommandGroup(after: .newItem) {
ShowSheetButton()
.keyboardShortcut("n", modifiers: [.command, .shift])
}
}
}
}
将纸张直接放在
ContentView
上:
@main
struct The_ThingApp: App {
@State private var isShowingSheet = false
var body: some Scene {
WindowGroup {
ContentView()
// here VV
.sheet(isPresented: $isShowingSheet) {
VStack {
Text("Some stuff to be shown")
.font(.title)
.padding(50)
Button("Dismiss",
action: { isShowingSheet.toggle() })
}
}
}
.commands {
CommandMenu("Info") {
Button("Get Info") {
print("getting info")
isShowingSheet.toggle()
}
}
}
}
}
我相信,我想出了一个使用绑定的更简单的系统。
首先创建应用程序代码(基本上是新应用程序的 Hello World 代码的一部分)。
import SwiftUI
@main
struct sheetFromMacOSApp: App {
@State var displaySheet = false
var body: some Scene {
WindowGroup {
ContentView(displaySheet: $displaySheet)
}
.commands{
CommandGroup(replacing: .appInfo) {
Button(action: {
displaySheet.toggle()
}) {
Text("CLICK ME")
}
}
}
}
}
它使用的是一个 @State,它是名为
ClICK ME
的菜单的一部分(不是很原始,但当然,为什么不呢?)
不同的是,在ContentView中我们传递变量
displaySheet
作为参数。这意味着每个人都有一个真理来源(一个真正的布尔值来统治他们所有人)。
我们的内容视图如下所示。
struct ContentView: View {
@Binding var displaySheet: Bool
var body: some View {
VStack {
Text("Push The Button!")
.sheet(isPresented: $displaySheet, content: {
Text("Hello World")
.frame(width: 100, height: 100)
Button("Dismiss", action: {displaySheet.toggle()})
})
Button("Push Me", action: {displaySheet.toggle()})
}
.padding()
.frame(width: 200, height: 200)
}
}
struct ContentView_Previews: PreviewProvider {
@State static var displaySheet = false
static var previews: some View {
ContentView(displaySheet: $displaySheet)
}
}
我们传入
displaySheet
作为绑定,以便每个人都知道什么是什么。最酷的是,您可以将视图中的工作表作为按钮触发,或者在菜单中触发它。无论哪种方式都有效。
或者,如果您不需要按钮,只需将其删除即可。床单不在乎。
此代码已在 macOS 和 iOS 中使用 Xcode 15.4 进行了测试。
至于PER DOCUMENT状态,这可能会回答你的问题,但我没有尝试过,也不能保证它。