从菜单项调用工作表

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

我有一个 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() })
                    }
                }
            }
       }
    }
}

如何显示菜单项中的工作表?

但是,如果表格不是实现这一点的方法(我认为考虑到我需要展示的内容的简单性,那就是它),您建议我如何做?我尝试创建一个新视图,就像我在首选项窗口中所做的那样,但我也无法从菜单中调用它。

macos swiftui
3个回答
3
投票

这个答案有点晚了,但希望能提供一些与多窗口应用程序配合良好的指导。观看完 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])
            }
        }
    }
}

3
投票

将纸张直接放在

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()
                }
            }
        }
    }
}

0
投票

我相信,我想出了一个使用绑定的更简单的系统。

首先创建应用程序代码(基本上是新应用程序的 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状态,这可能会回答你的问题,但我没有尝试过,也不能保证它。

© www.soinside.com 2019 - 2024. All rights reserved.