SwiftUI 2:在新窗口中打开视图的方式

And*_*rew 14 navigation macos scene swift swiftui

假设我有一个应用程序

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

@SceneBuilder var body: some Scene {
    WindowGroup {
        BookStoreView( model: storeVM )
    }
    
    #if os(macOS)
    Settings {
        SettingsView(model: config)
    }   
    #endif
}
Run Code Online (Sandbox Code Playgroud)

BookStore 有一个 Grid,其中有很多书籍保存在某个 DB 中。

BookView 可以通过以下方式启动:

BookView(model: bookViewModel)
Run Code Online (Sandbox Code Playgroud)

目标:在新的分离窗口中打开 BookView(例如单击按钮)。我怎样才能做到这一点?


奖金问题:如何SettingsView(model: config)从代码中打开?


PS:NavigationLink对我来说不是解决方案,因为我没有使用NavigationView.

Asp*_*eri 7

更新:Xcode 14 / macOS 13

现在我们可以显式打开所需的窗口,为其提供标识符并在openWindow环境操作中使用它。

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
        }

        Window("Book Viewer", id: "book") { // << here !!
            BookView(model: appState.selectedBook)
        }

        // also possible variant with injected model for group
        // WindowGroup("Book Viewer", id: "book", for: Book.self) {  book in // << here !!
        //   BookView(model: book)
        // }
    }
}

struct ContentView: View {
    @EnvironmentObject var appState: AppState

    @Environment(\.openWindow) private var openWindow   // << !!

    var body: some View {

        // assuming selection in grid somewhere here to
        // appState.selectedBook

        Button("Open Book") {
            openWindow(value: "book")       // << here !!

        // for group variant with injected value
        // if let book = self.selectedBook {
        //    openWindow(value: "book", book)       // << here !!
        // }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不,编译错误;但无论如何,这都不是一个很好的解决方案,即使它能工作,真正更容易和更干净的代码将是在使用 AppKit 的情况下...是否真的没有更好的方法在 swiftUI 中打开全新的窗口? (3认同)
  • 这对我来说编译得很好,但我没有弹出任何第二个窗口。(我使用的是 Big Sur beta、Xcode 12.2 beta) (2认同)

hil*_*ark 5

我找到了这个答案,它在能够打开新窗口方面对我有用:https://developer.apple.com/forums/thread/651592 ?answerId=651132022#651132022

我正在xcode 12.3运行Swift 5.3大苏尔。

以下是如何进行设置的示例,以便ContentView可以使用 中的按钮来打开OtherView窗口。

@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!")
    }
}

Run Code Online (Sandbox Code Playgroud)

注意:请确保遵循链接答案中包含的 URL 方案说明(为方便起见,在此处引用):

现在,在“项目”->“信息”->“URL 类型”中,test在“URL 方案”字段(以及标识符字段)中输入内容,以向系统注册我们的应用程序。

我通过编辑Info.plist文件并在其中添加内容来实现这一点,即URL types-> URL Schemes...:

信息表

  • 首先 - 这是一个有趣的解决方案,感谢它。但看起来它没什么用,直到我们无法将 viewModel 发送到窗口中。您知道如何将它与 viewModel 一起使用吗? (2认同)