Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Scene/WindowGroup in SwiftUI 2?

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.

like image 666
Andrew Avatar asked Jul 11 '20 16:07

Andrew


People also ask

What is a WindowGroup in SwiftUI?

The default implementation of a WindowGroup allows multiple instances of the window to be created (either using ⌘N , or the "Show Tab Bar" command). Each instance of a window created from a window group contains the same SwiftUI hierarchy, but maintains an independent state.

What are scenes in SwiftUI?

Overview. On-screen Scene s are the building blocks of any app built entirely in SwiftUI. They can look different depending on the platform the app is running on. For example, in iOS, the screen usually only displays one scene at a time. In macOS, every window in an app might be a different scene.

What are iOS scenes?

A scene contains the windows and view controllers for presenting one instance of your UI. Each scene also has a corresponding UIWindowSceneDelegate object, which you use to coordinate interactions between UIKit and your app. Scenes run concurrently with each other, sharing the same memory and app process space.

Can you use SwiftUI on Windows?

While you can't use SwiftUI on Windows, there many other ways to create iOS apps. Regardless of the language or framework you use, you ultimately need macOS running somewhere as the tools to build an iOS app are only on macOS.


Video Answer


1 Answers

  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.

like image 84
Andrew Avatar answered Oct 26 '22 12:10

Andrew