16

There is several objects in SwiftUI 2 like Scene and WindowGroup as some sort of Scene.

After reading documentation and looking WWDC2020 video related to scenes I see hierarchy by the following way :

Single App => One or multiple scenes => Hierarchy of Views (or a few)

Each scene contains the root view of a view hierarchy and has a life cycle managed by the system. Each scene can be displayed with different ways depends to the platform.

  1. In case of few children of WindowGroup scene - how it's choosing the way to display them? ( vertically / horizontally )? And how to control it manually?

I'm not sure that this is controlled with HStack and VStack because of in my test project I got different result instead expected by some reason.

  1. How I can control Scene displayed? As example app have 2 scenes - each WindowGroup with 2 Views in it. How can I switch from one scene to another in the same window of macOS?

  2. How to open second scene in new window using SwiftUI?

  3. Why do we need WindowGroup at all? Isn't it a just a set of Views?

  4. How to work with them in general?

Or where I can read more details than written in documentation or WWDC 1 min video (from 2.00 to 3.05) as there is not enough information to understand the topic.

Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
  • @matt Have checked WWDC 2019 - https://developer.apple.com/videos/wwdc2019/ and closest video to the topic on my opinion is https://developer.apple.com/videos/play/wwdc2019/259/ , but it's not related to SwiftUI. Even so, I have looked wwdc2020 related videos, I have checked official documentation and still does not understand, thats why I have created the question. And also I'm not understand why this is bad enough question to downvote it or close it. – Andrew_STOP_RU_WAR_IN_UA Jul 12 '20 at 00:06
  • @matt Also, please check, that "Scene" marked as "beta" in documentation of SwiftUI. So this is new feature of SwiftUI. – Andrew_STOP_RU_WAR_IN_UA Jul 12 '20 at 00:13
  • 3
    @matt Yes, in first one man talks only 65 seconds about Scene and WindowGroup with a little bit information, another video is 15 mins about DocumentGroup. And both didn't answer how to work with Scene/WindowGroup correctly. How to open another scene / how WindowGroup choose the way do display views (vertically or horisontaly), how to set the way of display manually(vertical,horisontal) [on the video is displayed horisontally , in my test project - vertically], etc, etc. There are no relevant information there, that's why I'm asking here. – Andrew_STOP_RU_WAR_IN_UA Jul 12 '20 at 01:20
  • 1
    I already watched video 5 times and didn't get any answers on my questions. – Andrew_STOP_RU_WAR_IN_UA Jul 15 '20 at 12:03
  • @matt, I have tried to focus on one sub-question https://stackoverflow.com/questions/62915324/swiftui-2-the-way-to-open-view-in-new-window and looks like it's still have no good answers. A single one answer, but even is a pretty lame hack. Maybe you have an answer on question with a such form? – Andrew_STOP_RU_WAR_IN_UA Jul 16 '20 at 00:17
  • 4
    I don't think @matt has dug into this. At a glance it looks like everything is there, but it's not. Anyway, I'm dealing with the same issues. Any luck? I can't find any documentation about showing/hiding scenes or creating a single window/scene on macOS. – Austin Aug 23 '20 at 22:52

1 Answers1

4
  1. still have no idea how it's choosing the way to display them
  2. There is no easy way to do this. You need to create superview and change child view in it. Sth like:
    @SceneBuilder var body: some Scene {
        WindowGroup {
            NavigatorView()
        }
    }

    enum DisplayedScene {
        case Browser
        case Status(url: URL)
    }


    struct NavigatorView: View {
        @State var displayedScene = DisplayedScene.Browser

        var body: some View {
            VStack {
                switch(model.displayedScene) {
                case DisplayedScene.Browser:
                    BrowserView(model: browserViewModel, wndId: id)
                case DisplayedScene.Status(let url):
                    VStack {
                        StatusView(url: url, wndId: id)
                    
                        Button("back") { AppCore.signals.send(signal: Signal.TaoGit.Navigator.ShowBrowser(wndId: id) ) }
                    }
                default:
                    Text("ERROR")
                }
            }.transition(.identity)
            .animation(.easeInOut)
        }
    }

so all you need to change view displayed is to send signal to change displayedScene.

Another way is to do displayedScene as EnvironmentVariable. But in this case you will be able to work with ONLY ONE INSTANCE of window correctly. So this is a bad way. But can be OK for someone.

  1. How to open second scene in new window using SwiftUI? -- there are no easy way to do this. You need to use handlesExternalEvents. Sample:
import SwiftUI

@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)
        }
    }
}
  1. Why do we need WindowGroup at all? Isn't it a just a set of Views? -- It's telling to swiftUI that exactly this view can be shown as separated Window.

  2. How to work with them in general? -- only with lot of hacks. Looks like SwiftUI is works really bad with MacOS.

Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
  • 1
    Hi Andrew, Re 4. - it's a semantic container, bit like Form and List, confers a bunch standard capabilities on the View hierarchy contained within it that _should_ behave correctly across all of Apple's platforms. At moment, for WindowGroup that's things like independent @StateObjects, cmd+N opening new windows. In the future hopefully more. Regarding 5. the best source of semi-official guidance I've been able to find are written up notes from this years digital lounge over here https://www.swiftui-lab.com/random-lessons#window-1 . If found anything better would be interested :-) – shufflingb Aug 06 '21 at 16:19