Понимание Scene / WindowGroup в SwiftUI 2?
В SwiftUI 2 есть несколько объектов, таких как Scene и WindowGroup, как своего рода Scene.
Прочитав документацию и просмотрев видео WWDC2020, относящееся к сценам, я вижу иерархию следующим образом:
Одно приложение => Одна или несколько сцен => Иерархия просмотров (или несколько)
Каждая сцена содержит корневое представление иерархии представлений и имеет жизненный цикл, управляемый системой. Каждая сцена может отображаться по-разному в зависимости от платформы.
- В случае нескольких дочерних элементов сцены WindowGroup - как она выбирает способ их отображения? (вертикально / горизонтально)? А как управлять вручную?
Я не уверен, что это контролируется с помощью HStack и VStack, потому что в моем тестовом проекте я получил другой результат вместо ожидаемого по какой-то причине.
Как я могу управлять отображаемой сценой? В качестве примера приложение имеет 2 сцены - каждая WindowGroup с 2 представлениями в ней. Как переключаться с одной сцены на другую в одном окне macOS?
Как открыть вторую сцену в новом окне с помощью SwiftUI?
Зачем нам вообще нужна WindowGroup? Разве это не просто набор просмотров?
Как вообще с ними работать?
Или где я могу прочитать больше подробностей, чем написано в документации или 1-минутном видео WWDC (с 2,00 до 3,05), поскольку информации недостаточно для понимания темы.
1 ответ
- до сих пор не знаю, как он выбирает способ их отображения
- Нет простого способа сделать это. Вам нужно создать супервизор и изменить в нем дочерний вид. Нравится:
@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
. Но в этом случае вы сможете корректно работать ТОЛЬКО с ОДНИМ ЭКЗЕМПЛЯРОМ окна. Так что это плохой способ. Но может быть для кого-то нормально.
- Как открыть вторую сцену в новом окне с помощью 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)
}
}
}
Зачем вообще нужна WindowGroup? Разве это не просто набор просмотров? -- Это говорит swiftUI, что именно это представление может отображаться как отдельное окно.
Как вообще с ними работать? - только с большим количеством хаков. Похоже, SwiftUI очень плохо работает с MacOS.