如何在 SwiftUI、macOS 中打开另一个窗口?

Rob*_*b N 6 macos swiftui

我想在 macOS 上的 SwiftUI 应用程序中显示具有不同内容的第二个窗口。我找不到任何关于此的文档。下面的尝试不起作用。有谁知道怎么做?

class AppState: ObservableObject {
    @Published var showSecondWindow: Bool = false
}

@main
struct MultipleWindowsApp: App {
    @StateObject var appState = AppState()
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(appState)
        }
        WindowGroup {
            if appState.showSecondWindow {
                SecondContent()
            }
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var appState: AppState
    var body: some View {
        VStack {
            Text("Hello, world!")
            Button("Open 2nd Window") {
                appState.showSecondWindow = true
            }
        }.padding()
    }
}

struct SecondContent: View {
    var body: some View {
        Text("Hello, from window #2.")
    }
}
Run Code Online (Sandbox Code Playgroud)

bau*_*sic 18

这是一个用于创建窗口NSViewController、分配标题并打开它的扩展。

extension View {
    
    @discardableResult
    func openInWindow(title: String, sender: Any?) -> NSWindow {
        let controller = NSHostingController(rootView: self)
        let win = NSWindow(contentViewController: controller)
        win.contentViewController = controller
        win.title = title
        win.makeKeyAndOrderFront(sender)
        return win
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

Button("Open 2nd Window") {
    SecondContent().openInWindow(title: "Win View", sender: self)
}
Run Code Online (Sandbox Code Playgroud)

关闭窗口

NSApplication.shared.keyWindow?.close()
Run Code Online (Sandbox Code Playgroud)


Leo*_*XUI 16

在 Xcode 13 beta、SwiftUI 3.0 上测试

在遇到这种情况后,我在互联网上找到了一些答案,这对我有用:

在 @main (MyAppApp) 文件中添加您需要的数量WindowGroup("Window Name")

import SwiftUI

@main
struct MyAppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        WindowGroup("Second Window") {
            SecondWindow()
        }.handlesExternalEvents(matching: Set(arrayLiteral: "SecondWindow"))
        
        WindowGroup("Third Window") {
            ThirdWindow()
        }.handlesExternalEvents(matching: Set(arrayLiteral: "ThirdWindow"))

}
Run Code Online (Sandbox Code Playgroud)

每个中应该放置什么WindowGroup?:

WindowGroup("SecondWindow") /*Any name you want to be displayed at the top of the window.*/ {
            SecondWindow() //View you want to display.
}.handlesExternalEvents(matching: Set(arrayLiteral: "SecondWindow")) //Name of the view without ().
Run Code Online (Sandbox Code Playgroud)

现在,在 MyAppApp 文件的末尾(在 之外struct MyAppApp: App)添加以下内容enum

enum OpenWindows: String, CaseIterable {
    case SecondView = "SecondView"
    case ThirdView   = "ThirdView"
    //As many views as you need.

    func open(){
        if let url = URL(string: "myapp://\(self.rawValue)") { //replace myapp with your app's name
            NSWorkspace.shared.open(url)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

将以下内容添加到您的Info.plist

信息表

将 myapp 替换为您的应用程序名称。

用法

Button(action: {
            OpenWindows.SecondView.open()
       }){
            Text("Open Second Window")           
         }
Run Code Online (Sandbox Code Playgroud)


iph*_*aaw 2

这将打开一个新窗口:

import SwiftUI

struct ContentView: View
{
    var body: some View
    {
        Button(action: {openMyWindow()},
               label: {Image(systemName: "paperplane")})
            .padding()
    }
}

func openMyWindow()
{
    var windowRef:NSWindow
    windowRef = NSWindow(
        contentRect: NSRect(x: 100, y: 100, width: 100, height: 600),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    windowRef.contentView = NSHostingView(rootView: WindowView())
    windowRef.makeKeyAndOrderFront(nil)
}

struct WindowView: View
{
    var body: some View
    {
        Text("Hello World")
            .padding()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果这是“旧”方式,您可以添加“新”方式吗? (4认同)
  • 如果“新”方式是使用自定义 URL 方案,那么这是创建新窗口的糟糕方式。这意味着您需要将每个窗口“硬编码”到“info.plist”文件中。只是感觉各方面都不对劲。我宁愿只使用“NSHostingView”,而不是将窗口添加到“info.plist”。 (3认同)
  • 这是 SwiftUI 2.0 之前的老方法。 (2认同)