macOS 应用程序的 SwiftUI:关闭窗口并打开另一个窗口时的用户 @EnvironmentObject
Posted
技术标签:
【中文标题】macOS 应用程序的 SwiftUI:关闭窗口并打开另一个窗口时的用户 @EnvironmentObject【英文标题】:SwiftUI for macOS app: User @EnvironmentObject when closing a window and opening another 【发布时间】:2020-01-07 18:16:03 【问题描述】:如果您必须输入凭据,我的应用程序以登录屏幕开始,如果登录成功,当前窗口将关闭并打开另一个窗口。在新窗口中,我需要用户模型中的一些(在登录期间使用)来执行对 api 的其他请求(基本身份验证)。
层次结构:ContentView -> LoginView() -> MainPageView()
AppDelegateCode:
let contentView = ContentView()
let userVM = CreateUserViewModel()
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView.environmentObject(userVM))
window.makeKeyAndOrderFront(nil)
内容查看代码:
struct ContentView: View
var body: some View
LoginView()
登录查看代码:
struct LoginView: View
@EnvironmentObject var userVM: CreateUserViewModel
//@ObservedObject var userVM: CreateUserViewModel = CreateUserViewModel()
@State private var showSignUpSheet: Bool = false
var body: some View
VStack
Text("LubeMarker")
.font(.title)
HStack
Text("Email")
TextField("", text: self.$userVM.email)
HStack
Text("Pass")
.padding([.trailing], 4)
SecureField("", text: self.$userVM.password)
HStack
Button("Login")
self.userVM.loginUser()
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
if self.userVM.loginUserMessage == "Login Successful"
NSApplication.shared.keyWindow?.close()
let window = NSWindow(contentRect: NSRect(x: 20, y: 20, width: 480, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Primary Window")
window.contentView = NSHostingView(rootView: MainPageView().environmentObject(self.userVM))
window.makeKeyAndOrderFront(nil)
Button("Sign Up")
self.showSignUpSheet = true
Text(userVM.loginUserMessage)
.padding([.leading, .trailing], 60)
//.frame(width: 300, height: 200)
.sheet(isPresented: self.$showSignUpSheet)
SignUpView(showSingUpSheet: self.$showSignUpSheet)
当我想在 MainPageView 的子视图中使用 @EnvironmentObject 时,遇到以下错误:
Thread 1: Fatal error: No ObservableObject of type CreateUserViewModel found.
A View.environmentObject(_:) for CreateUserViewModel may be missing as an ancestor of this view.
我认为错误是由于 LoginView 和 MainPageView 之间没有父子关系,因为我关闭了窗口并在登录按钮操作块中打开了另一个窗口。
有没有办法在 swiftUI 中链接两个视图?
【问题讨论】:
【参考方案1】:找到了解决办法。在 LoginView 中,我使用 @ObservedObject 属性包装器声明了一个 CreateUserViewModel 实例并将其传递给 MainPageView,这还需要在 CreateUserViewModel 类型的 MainPageView 中添加一个新属性。
登录视图:
@ObservedObject var userVM: CreateUserViewModel = CreateUserViewModel()
@State private var showSignUpSheet: Bool = false
var body: some View
HStack
Button("Login")
self.userVM.loginUser()
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
if self.userVM.loginUserMessage == "Login Successful"
let mainPage = MainPageView(userVM: self.userVM)
NSApplication.shared.keyWindow?.close()
let window = NSWindow(contentRect: NSRect(x: 20, y: 20, width: 480, height: 300), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Primary Window")
window.contentView = NSHostingView(rootView: mainPage)
window.makeKeyAndOrderFront(nil)
主页面视图:
struct MainPageView: View
@State var selectedProduct: ProductTypes?
@State var showAddProductSheet: Bool = false
var userVM: CreateUserViewModel
var body: some View
VStack(spacing: 0)
HStack
Button("Add Product")
self.showAddProductSheet = true
.padding()
Spacer()
Text("Hello World")
.frame(minWidth: 480, minHeight: 300)
.sheet(isPresented: self.$showAddProductSheet)
AddProductView(showAddProductSheet: self.$showAddProductSheet).environmentObject(self.userVM)
并从 MainPageView 将 userVM 作为环境对象传递给其他视图。我似乎只能通过使用@ObservedObject 将关闭窗口与新窗口连接起来。
如果有办法在这种情况下使用@EnvironmentObject,我仍然很好奇。
【讨论】:
以上是关于macOS 应用程序的 SwiftUI:关闭窗口并打开另一个窗口时的用户 @EnvironmentObject的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 生命周期中删除 macOS 中的最大化、最小化和关闭按钮?
如何在 SwiftUI 中隐藏 macOS 中视图/窗口的状态栏?