Loading...

Two ways to open a window programmatically in SwiftUI

question swiftui macos
Ram Patra Published on September 3, 2024

SwiftUI provides an openWindow environment variable on macOS that allows you to open windows programmatically. Here’s how you can use it to open a new window when a button is clicked:

Steps to Use openWindow Environment Variable

  1. Define a WindowGroup Scene: Create a WindowGroup in your App struct for the new window you want to open.

  2. Use the openWindow Environment Variable: Utilize the openWindow environment variable in your view to open the new window.

  3. Button to Trigger Window Opening: Add a button in your main view that calls the openWindow function to present the new window.

Example Implementation

Here’s an example of how to open a new window using the openWindow environment variable:

import SwiftUI

@main
struct WindowExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        WindowGroup("New Window") {
            NewWindowView()
        }
        .handlesExternalEvents(matching: ["newWindow"])
    }
}

struct ContentView: View {
    @Environment(\.openWindow) private var openWindow
    
    var body: some View {
        VStack {
            Button("Open New Window") {
                openWindow(id: "newWindow")
            }
            .padding()
        }
    }
}

struct NewWindowView: View {
    var body: some View {
        Text("This is a new window!")
            .frame(minWidth: 200, minHeight: 200)
            .padding()
    }
}

Explanation:

  1. @Environment(\.openWindow):
    • The openWindow environment variable provides a way to programmatically open a new window. It allows you to specify the id of the window you want to open.
  2. WindowGroup:
    • The WindowGroup("New Window") defines the content for the new window. The handlesExternalEvents(matching: ["newWindow"]) makes this window group respond to the "newWindow" event.
  3. ContentView:
    • This is your main view containing a button. When the button is clicked, the openWindow(id: "newWindow") function is called, which opens the window associated with the id "newWindow".
  4. NewWindowView:
    • This view represents the content that will be displayed in the new window when it is opened.

Running the App:

  • Clicking the “Open New Window” button in the ContentView triggers the openWindow(id: "newWindow") function, which opens a new window displaying the NewWindowView content.

Notes:

  • handlesExternalEvents(matching:): This method is used to specify which external events (like window opening events) this WindowGroup should handle. The id you use in openWindow(id:) should match the event you define here.

  • macOS Specific: The openWindow environment variable is available on macOS, and this method is specific to macOS applications.

This approach is straightforward and leverages SwiftUI’s native capabilities to manage windows, making it an elegant solution for opening windows programmatically in a macOS app.

Second Approach

In SwiftUI, you can open a new window when a button is clicked by leveraging the @State property to manage the presentation of the window. Here’s how you can do it:

Steps to Open a Window on Button Click

  1. Define a WindowGroup Scene: In your App struct, you define a WindowGroup that represents the window you want to open.

  2. Manage Window Presentation: Use a @State property in your main view to control when the new window should be presented.

  3. Button to Trigger Window Opening: Add a button in your view that toggles the @State property, causing the window to appear.

Example Implementation

Here’s a simple example where clicking a button opens a new window:

import SwiftUI

@main
struct WindowExampleApp: App {
    @State private var showNewWindow = false
    
    var body: some Scene {
        WindowGroup {
            ContentView(showNewWindow: $showNewWindow)
        }
        
        // This defines the new window
        WindowGroup("New Window") {
            NewWindowView()
        }
        .handlesExternalEvents(matching: ["openNewWindow"])
    }
}

struct ContentView: View {
    @Binding var showNewWindow: Bool
    
    var body: some View {
        VStack {
            Button("Open New Window") {
                showNewWindow = true
                openNewWindow()
            }
            .padding()
        }
    }
    
    private func openNewWindow() {
        if let url = URL(string: "myapp://openNewWindow") {
            NSWorkspace.shared.open(url)
        }
    }
}

struct NewWindowView: View {
    var body: some View {
        Text("This is a new window!")
            .frame(minWidth: 200, minHeight: 200)
            .padding()
    }
}

Explanation:

  1. @State private var showNewWindow = false:
    • This state variable tracks whether the new window should be opened.
  2. ContentView:
    • The ContentView contains a button that toggles the showNewWindow state and calls openNewWindow().
  3. WindowGroup:
    • The WindowGroup("New Window") defines a new window in the app, and it’s configured to respond to the "openNewWindow" event.
  4. openNewWindow() Function:
    • This function opens the new window by triggering the event that corresponds to the "openNewWindow" handler in the WindowGroup.
  5. NewWindowView:
    • This view represents the content of the new window that appears when the button is clicked.

Running the App:

  • When you click the “Open New Window” button, the app triggers the URL scheme (myapp://openNewWindow), causing the WindowGroup with the "openNewWindow" event to open a new window displaying NewWindowView.

Notes:

  • handlesExternalEvents(matching:): This method allows the app to handle custom URLs to trigger the opening of the new window. The URL scheme (myapp://openNewWindow) is just an example. You need to make sure that this scheme is unique and does not conflict with other URL schemes in your app or other apps.

  • macOS Specific: The above code is specific to macOS. On iOS, opening new windows is handled differently, typically using NavigationView for navigation or presenting new views modally.

This method offers a simple and effective way to open new windows in a SwiftUI macOS app when a button is clicked.

Presentify

Take your presentation to the next level.

FaceScreen

Put your face and name on your screen.

ToDoBar

Your to-dos on your menu bar.

Ram Patra Published on September 3, 2024
Image placeholder

Keep reading

If this article was helpful, others might be too

question swiftui swift September 8, 2024 How to loop through an enum in SwiftUI?

In SwiftUI, looping through an enum is not directly possible without some extra work because enums in Swift don’t inherently support iteration. However, you can achieve this by making the enum CaseIterable, which automatically provides a collection of all cases in the enum.

question swiftui macos September 3, 2024 How to open and close windows programmatically in SwiftUI?

To open or close a window programmatically from outside that window using environment variables, you need to leverage the new openWindow (macOS 13+) and dismissWindow (macOS 14+) environment variables. This environment variables allow you to programmatically open and close a window by its identifier.

question swiftui swift May 29, 2022 How to open a window in SwiftUI using NSWindowController?

Although many things in SwiftUI are idiomatic and straightforward, showing your view in a new window needs a bit of coding to do. Hence, this short post.