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 swift class 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 @main struct TestApp: App { var body: some Scene { WindowGroup { RootView() } } } var useWindow1: Bool = true struct 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 @main struct 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.