假设我有一个应用程序
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
}
BookStore 有一个网格,其中在某个数据库中保存了很多书籍。
BookView可以通过以下方式启动:
BookView(model: bookViewModel)
目标:在新的单独窗口中打开 BookView(例如单击按钮)。我怎样才能做到这一点?
奖励问题: 如何从代码中打开
SettingsView(model: config)
?
PS:
NavigationLink
对我来说不是解决方案,因为我没有使用NavigationView
。
现在我们可以显式打开所需的窗口并为其提供标识符,并在
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 !!
// }
}
}
}
我找到了这个答案,它在能够打开新窗口方面对我有用:https://developer.apple.com/forums/thread/651592?answerId=651132022#651132022
我正在
xcode 12.3
、Swift 5.3
运行 Big Sur。
以下是如何设置的示例,以便可以使用
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!")
}
}
注意: 请务必遵循链接答案中包含的 URL 方案说明(为方便起见,在此处引用):
现在在“项目”->“信息”->“URL 类型”中,在“URL 方案”字段(以及标识符字段)中输入
,以向系统注册我们的应用程序。test
我通过编辑
Info.plist
文件并在其中进行添加来实现此目的,即 URL types
-> URL Schemes
...:
我使用了 hillmark 的答案中的代码,得到了比他的代码更好的结果。
即使此代码仍然不是答案,这可能对某人有用。
_
通常,如果您需要使用基于 ViewModel 的 View,此代码对您来说将毫无用处。
但是如果您只需要使用视图 - 这是一个很好的解决方案。
@main
struct TestAppApp: App {
var body: some Scene {
WindowGroup {
MainView()
}
// magic here
.handlesExternalEvents(matching: Set(arrayLiteral: Wnd.mainView.rawValue))
WindowGroup {
HelperView()
}
// magic here
.handlesExternalEvents(matching: Set(arrayLiteral: Wnd.helperView.rawValue))
}
}
extension TestAppApp {
struct MainView: View {
var body: some View {
VStack {
Button("Open Main View") {
// magic here
Wnd.mainView.open()
}
Button("Open Other View") {
// magic here
Wnd.helperView.open()
}
}
.padding(150)
}
}
struct HelperView: View {
var body: some View {
HStack {
Text("This is ") + Text("Helper View!").bold()
}
.padding(150)
}
}
}
// magic here
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)
}
}
}
要使用此代码,您需要具备以下条件:
我最近在 swiftui 中遇到了类似的问题,我想创建一个新的桌面级窗口,我想终于找到了解决方案。
Button("Show Bookmark") {
// create a new NSPanel
let window = NSPanel(contentRect: NSRect(x: 0, y: 0, width: 500, height: 500), styleMask: [.fullSizeContentView, .closable, .resizable, .titled], backing: .buffered, defer: false)
// the styleMask can contails more, like borderless, hudWindow...
window.center()
// put your swiftui view here in rootview
window.contentView = NSHostingView(rootView: BookmarkView())
window.makeKeyAndOrderFront(nil)
// if you want to close the window after delay
DispatchQueue.main.asyncAfter(deadline: .now()) {
window.close()
}
}
Xcode 16 中的新功能
Window("My super duper window", id: "myWnd") {
Text("New in this version…")
}
struct ContentView: View {
@Environment(\.openWindow) var openWindow
var body: some View {
Button("Show another one wnd") {
openWindow(id: "myWnd")
}
}
}