Monday, May 23, 2022

How to Open a Window in SwiftUI

Rob N:

I’d like to show a second window with different content in a SwiftUI app on macOS. I can’t find any documentation on this.

Malcolm Hall (tweet, forum):

In your ContentView create a button and open a URL for your app and another View e.g. Viewer to be shown in the window we will open[…]

[…]

In your App add another WindowGroup for your viewer and set it to enable handling of external launch events (an internal event in our case).

[…]

Now in Project->Info->URL Types type in myappname in the URL Schemes field (and the identifier field too) to register our app with the system.

Tony Arnold:

Is that a workaround? That’s a workaround for missing API, right? 😳

Malcolm Hall:

No, its a declarative state-driven API that handles the reason why you would want a new window. You aren’t going to get an imperative open window in SwiftUI because that’s not how it is designed.

Marcin Krzyzanowski:

I’m not convinced this is designed. It’s more like something that happens, but doesn’t really is well thought for the scenario where the app needs to open multiple windows. URL cannot be the way. It’s missing window state management. Windows are hierarchical. This is not.

It’s great that there is a way to do this without calling into AppKit, but using URLs seems gross.

Khoa Pham:

A common trick is to use an NSViewRepresentable to get underlying view.window and attach this to our SwiftUI view

[…]

For a common macOS SwiftUI app with a search bar on the toolbar and a normal settings screen, here’s how I usually do

Setup NSWindow programmatically

Previously:

Update (2022-07-12): Natalia Panferova (tweet):

In macOS 13 we finally have a way to programmatically present a window in SwiftUI. We can call the new openWindow action from the environment and pass it a scene id or a value.

Previously:

4 Comments RSS · Twitter

Ben Kennedy

Comedy like this reaffirms confidence in the almost total lack of attention that I've paid to SwiftUI since its debut.

I actually think it is only slightly wrong, instead of a URL, it should be a NSUserActivity. But those and URLs are semantically almost the same.

And yes, there is always AppKit. Which just works for that, not sure why people don't just use it? It's a feature not a bug that it can be used.

The worse thing IMO is that despite moving regular restoration to NSUserActivities in UIKit, which makes sense, is that SwiftUI only has @SceneState and no way for controllers to get access to that, w/o hack-patching things in. I.e. you don't get access to a scene.

Is the discussion there suggesting that SwiftUI was effectively made with the assumption that all apps would be contained within a single parent window?

We've seen what happens in, I suspect Catalyst apps, where when you have multiple windows from a single app open, moving the parent window on screen, also moves all the child windows (but not the reverse) as if they're all on a single sheet of glass.

A lot of recent UI frameworks seem to suffer this "we've mostly designed this with mobile in mind so multiple windows are an afterthought" syndrome. Xamarin Forms, Electron, Windows App SDK, etc. all shipped with limited multiple-window support.

What a world.

Leave a Comment