How do we decide what windows open on launch?
How do we decide what windows open on launch?
Code Block swift @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { Settings { } }
Code Block swiftclass AppWindow: NSWindow { init() { super.init(contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) makeKeyAndOrderFront(nil) isReleasedWhenClosed = false styleMask.insert(NSWindow.StyleMask.fullSizeContentView) title = "title placeholder" contentView = NSHostingView(rootView: ContentView()) }}
Code Block swift var body: some Scene { WindowGroup { ContentView().environmentObject(appState) } WindowGroup("File List") { if appState.showFileList { FileListView().environmentObject(appState) } } }
Code Block @mainstruct TestApp: App { var body: some Scene { WindowGroup { RootView() } }}var useWindow1: Bool = truestruct RootView: View { var body: some View { Group { if useWindow1 { Window1() } else { Window2() } } }}
Code Block NSApp.mainWindow?.windowController?.newWindowForTab(nil)
Code Block struct ContentView: View { @Environment(\.openURL) var openURL var body: some View { VStack { Button("Open Viewer") { if let url = URL(string: "myappname://viewer") { openURL(url) } } Text("Hello, world!") } .padding() }}struct Viewer: View { var body: some View { Text("Viewer") }}
Code Block @mainstruct GroupDefaultsTestApp: App { var body: some Scene { WindowGroup { ContentView() } WindowGroup("Viewer") { // other scene Viewer() } .handlesExternalEvents(matching: Set(arrayLiteral: "*")) }}
Tested on Xcode 13 beta, SwiftUI 3.0
After having being in this situation, I Frankensteined some answers that where all over the internet and this works for me:
On the @main (MyAppApp) file add the amount of WindowGroup("Window Name")
you need:
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")) }
What to place in every 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 ().
Now, at the end of the MyAppApp file (outside of the struct MyAppApp: App
) add the following 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) } } }
Add the following to your Info.plist
Replace myapp with your app's name.
Usage:
Button(action: { OpenWindows.SecondView.open() }){ Text("Open Second Window") }
I have found this also to work. Although I think SwiftUI needs a much better way of supporting multiple macOS Windows.
In your AppStruct, although any persistent struct or class can hold a window.
Limitations: No idea how to let the system determine the window position or whether it will autosave window information.
struct Radio_2App: App { let someWindow = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 580, height: 300), styleMask: [.titled, .closable], backing: .buffered, defer: false) var body: some Scene { WindowGroup() { SomeContentView() } func openWindow() { someWindow.contentView = NSHostingView(rootView: SomeOtherView()) self.someWindow.makeKeyAndOrderFront(nil) } }
view extension:
extension View { private func newWindowInternal(title: String, geometry: NSRect, style: NSWindow.StyleMask, delegate: NSWindowDelegate) -> NSWindow { let window = NSWindow( contentRect: geometry, styleMask: style, backing: .buffered, defer: false) window.center() window.isReleasedWhenClosed = false window.title = title window.makeKeyAndOrderFront(nil) window.delegate = delegate return window } func openNewWindow(title: String, delegate: NSWindowDelegate, geometry: NSRect = NSRect(x: 20, y: 20, width: 640, height: 480), style:NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable]) { self.newWindowInternal(title: title, geometry: geometry, style: style, delegate: delegate).contentView = NSHostingView(rootView: self) } }
call with:
Text("This is a swiftui text").openNewWindow(...)
Make sure to keep a strong reference to the window delegate, the window will keep only a weak ref.