SwiftUI 2:在新窗口中打开视图的方式
Posted
技术标签:
【中文标题】SwiftUI 2:在新窗口中打开视图的方式【英文标题】:SwiftUI 2: the way to open view in new window 【发布时间】:2020-11-04 23:29:20 【问题描述】:假设我有一个应用程序
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 有一个 Grid,其中有很多书籍保存在一些 DB 中。
BookView 可以通过以下方式启动:
BookView(model: bookViewModel)
目标:在新的分离窗口中打开 BookView(例如单击按钮)。我该怎么做?
奖金问题:
如何从代码中打开SettingsView(model: config)
?
PS:NavigationLink
不是我的解决方案,因为我没有使用 NavigationView
。
【问题讨论】:
【参考方案1】:我找到了这个答案,它对我来说可以打开一个新窗口: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 方案说明(为方便起见,此处引用):
现在在 Project->Info->URL Types 中的 URL Schemes 字段(以及标识符字段)中输入
test
以向系统注册我们的应用程序。
我通过编辑Info.plist
文件并在其中添加内容来实现这一点,即URL types
-> URL Schemes
...:
【讨论】:
非常感谢,我稍后会检查这个 首先 - 这是一个有趣的解决方案,感谢它。但看起来它没用,直到我们无法将 viewModel 发送到窗口中。你知道如何将它与 viewModel 一起使用吗?【参考方案2】:尝试以下方法(只是想法 - 无法测试)
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
WindowGroup("Book Viewer") // other scene
if appState.selectedBook != nil
Book(model: appState.selectedBook)
【讨论】:
不可能将if()直接放在WindowGroup()中,需要换行到另一个视图中;从可空模型打开初始化视图是不可能的——无论如何我都需要返回视图,但返回空视图是个坏主意——结果我会得到一个空窗口。返回 nil - 会抛出错误;它看起来像是一种使用以下方式的hacky方式(我的意思是那些注入)。但是感谢您的尝试 @Andrew,这是运行时错误,因为它可以在我身边编译吗? 否,编译错误;但无论如何,这并不是一个很好的解决方案,因为即使它可以工作......真的更容易和更干净的代码将是在使用 AppKit 的情况下......真的没有更好的方法来在 swiftUI 中打开全新的窗口? 这对我来说编译得很好,但我没有弹出任何第二个窗口。 (我使用的是 Big Sur 测试版,Xcode 12.2 测试版) @RobN 在 12.4 版本 + Big Sur 11.1 上面临同样的问题【参考方案3】:我玩过 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
@Environment(\.openURL) var openURL
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)
要使用此代码,您需要具备以下条件:
【讨论】:
您是否已经尝试使用深层链接来传递“详细信息”?例如。taotao://MainView/ShowBook/BlaBla
中的图书标识符。尝试在 MainVIew 中使用 .onOpenUrl(...)
处理深层链接。
不,我没有。我在我的应用程序中使用了另一个系统而不是这个。因为这对我来说仍然不够灵活。
详细信息也可以发送,只要它是一个有效的url。但要小心,在 safari 中使用该链接会打开您的应用程序。所以不要相信你得到的任何意见。以上是关于SwiftUI 2:在新窗口中打开视图的方式的主要内容,如果未能解决你的问题,请参考以下文章
在新选项卡/窗口中打开链接而不丢失当前 JSF 页面的视图范围
从 AppKit NSButton 打开新的 SwiftUI 窗口
如何使用asp.net MVC中的href从javascript在新窗口中打开打开的窗口