SwiftUI 2: the way to open view in new window

前端 未结 3 2028
既然无缘
既然无缘 2021-02-08 09:23

Lets imagine that I have an App

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

@SceneBuilder var body: some Scene {
    WindowGroup {
              


        
相关标签:
3条回答
  • 2021-02-08 09:34

    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...:

    0 讨论(0)
  • 2021-02-08 09:38

    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()
            }
            .handlesExternalEvents(matching: Set(arrayLiteral: Wnd.mainView.rawValue))
            
            WindowGroup {
                HelperView()
            }
            .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") {
                        Wnd.mainView.open()
                    }
                    
                    Button("Open Other View") {
                        Wnd.helperView.open()
                    }
                }
                .padding(150)
            }
        }
    
        struct HelperView: View {
            var body: some View {
                HStack {
                    Text("This is ") + Text("Helper View!").bold()
                }
                .padding(150)
            }
        }
    }
    
    
    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:

    0 讨论(0)
  • 2021-02-08 09:43

    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)
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题