Понимание Scene / WindowGroup в SwiftUI 2?

В SwiftUI 2 есть несколько объектов, таких как Scene и WindowGroup, как своего рода Scene.

Прочитав документацию и просмотрев видео WWDC2020, относящееся к сценам, я вижу иерархию следующим образом:

Одно приложение => Одна или несколько сцен => Иерархия просмотров (или несколько)

Каждая сцена содержит корневое представление иерархии представлений и имеет жизненный цикл, управляемый системой. Каждая сцена может отображаться по-разному в зависимости от платформы.

  1. В случае нескольких дочерних элементов сцены WindowGroup - как она выбирает способ их отображения? (вертикально / горизонтально)? А как управлять вручную?

Я не уверен, что это контролируется с помощью HStack и VStack, потому что в моем тестовом проекте я получил другой результат вместо ожидаемого по какой-то причине.

  1. Как я могу управлять отображаемой сценой? В качестве примера приложение имеет 2 сцены - каждая WindowGroup с 2 представлениями в ней. Как переключаться с одной сцены на другую в одном окне macOS?

  2. Как открыть вторую сцену в новом окне с помощью SwiftUI?

  3. Зачем нам вообще нужна WindowGroup? Разве это не просто набор просмотров?

  4. Как вообще с ними работать?

Или где я могу прочитать больше подробностей, чем написано в документации или 1-минутном видео WWDC (с 2,00 до 3,05), поскольку информации недостаточно для понимания темы.

1 ответ

  1. до сих пор не знаю, как он выбирает способ их отображения
  2. Нет простого способа сделать это. Вам нужно создать супервизор и изменить в нем дочерний вид. Нравится:
          @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)
        }
    }

поэтому все, что вам нужно, чтобы изменить отображаемый вид, это отправить сигнал для изменения displayedScene.

Другой способ - сделать displayScene как EnvironmentVariable. Но в этом случае вы сможете корректно работать ТОЛЬКО с ОДНИМ ЭКЗЕМПЛЯРОМ окна. Так что это плохой способ. Но может быть для кого-то нормально.

  1. Как открыть вторую сцену в новом окне с помощью SwiftUI? - нет простого способа сделать это. Вам нужно использовать handlesExternalEvents. Образец:
      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. Зачем вообще нужна WindowGroup? Разве это не просто набор просмотров? -- Это говорит swiftUI, что именно это представление может отображаться как отдельное окно.

  2. Как вообще с ними работать? - только с большим количеством хаков. Похоже, SwiftUI очень плохо работает с MacOS.

Другие вопросы по тегам