TransWikia.com

SwiftUI 2: the way to open view in new window

Stack Overflow Asked on December 25, 2021

Lets imagine that I have an App

var storeVM = BookStoreViewModel(bla1: bla1, bla2: bla2, bla3: bla3)

@SceneBuilder var body: some Scene {
    WindowGroup {
        BookStoreView( model: storeVM )
    }
    
    #if os(macOS)
    Settings {
        SettingsView(model: config)
    }   
    #endif
}

BookStore have a Grid with a lot of books saved in some DB.

BookView can be initiated by a following way:

BookView(model: bookViewModel)

Target: to open BookView IN A NEW SEPARATED WINDOW(as example by click on the button). How can I do this?


Bonus question:
How can I open SettingsView(model: config) from the code?


PS: NavigationLink is not solution for me because I not using the NavigationView.

3 Answers

I have played with code from hillmark's answer and got some better results than his code.

Even if this code is still not the answer, this may be useful for someone.

_

Generlly this code will be useless for you in case you need to work with View based on ViewModel.

But if you need to work with View only - this is a good solution.

@main
struct TestAppApp: App {
    var body: some Scene {
        WindowGroup {
            MainView()
        }
        // magic here
        .handlesExternalEvents(matching: Set(arrayLiteral: Wnd.mainView.rawValue))
        
        WindowGroup {
            HelperView()
        }
        // magic here
        .handlesExternalEvents(matching: Set(arrayLiteral: Wnd.helperView.rawValue))
    }
}

extension TestAppApp {
    struct MainView: View {
        @Environment(.openURL) var openURL
        
        var body: some View {
            VStack {
                Button("Open Main View") {
                    // magic here
                    Wnd.mainView.open()
                }
                
                Button("Open Other View") {        
                    // magic here
                    Wnd.helperView.open()
                }
            }
            .padding(150)
        }
    }

    struct HelperView: View {
        var body: some View {
            HStack {
                Text("This is ") + Text("Helper View!").bold()
            }
            .padding(150)
        }
    }
}



// magic here
enum Wnd: String, CaseIterable {
    case mainView   = "MainView"
    case helperView = "OtherView"
    
    func open(){
        if let url = URL(string: "taotao://(self.rawValue)") {
            print("opening (self.rawValue)")
            NSWorkspace.shared.open(url)
        }
    }
}

To work with this code you need to have the following:

enter image description here

enter image description here

Answered by Andrew on December 25, 2021

I found this answer, which worked for me in terms of being able to open a new window: https://developer.apple.com/forums/thread/651592?answerId=651132022#651132022

I'm on xcode 12.3, Swift 5.3, running Big Sur.

The following is an example of how to set things up so a button in the ContentView can be used to open the OtherView window.

@main
struct testApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        WindowGroup("OtherView") {
            OtherView()
        }
        .handlesExternalEvents(matching: Set(arrayLiteral: "*"))
    }
}

struct ContentView: View {
    @Environment(.openURL) var openURL

    var body: some View {
       Button("Other View") {
           if let url = URL(string: "test://otherview") {
               openURL(url)
           }
       }
    }
}

struct OtherView: View {
    var body: some View {
        Text("Other View!")
    }
}

Note: Make sure to follow the URL Scheme instructions included in the linked answer (quoted here for convenience):

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

I achieved this by editing the Info.plist file and making the additions there, i.e URL types -> URL Schemes...:

Info.plist

Answered by hillmark on December 25, 2021

Try something like the following (just idea - cannot test)

class BookViewModel: ObservableObject {} 

class AppState: ObservableObject {
    @Published var selectedBook: BookViewModel?
}

@main
struct SwiftUI2_MacApp: App {
    @StateObject var appState = AppState()

    @SceneBuilder 
    var body: some Scene {
        WindowGroup {         // main scene
            ContentView()
              .environmentObject(appState)   // inject to update
                                             // selected book
        }

        WindowGroup("Book Viewer") { // other scene
            if appState.selectedBook != nil {
                Book(model: appState.selectedBook)
            }
        }
    }
}

Answered by Asperi on December 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP