努力与SwiftUI实现全局通知视图

努力与SwiftUI实现全局通知视图,swiftui,Swiftui,我正在尝试实现一个可以显示在导航栏顶部的视图。让我们将此视图称为通知视图。从任何其他SwiftUI视图都可以轻松触发此视图。例如,在登录视图中,如果用户名和密码错误 在下面,您可以找到我到目前为止的代码。只有在Username和Password字段中输入值时,此代码的问题才可见。通知视图显示正确,但同时用户名和密码字段的值正在丢失 发生这种情况是因为整个视图树正在重新渲染,通过NavigationLink创建一个全新的LoginView实例,其中包含一个空的LoginModel 如何在Swift

我正在尝试实现一个可以显示在导航栏顶部的视图。让我们将此视图称为
通知视图
。从任何其他SwiftUI视图都可以轻松触发此视图。例如,在登录视图中,如果用户名和密码错误

在下面,您可以找到我到目前为止的代码。只有在
Username
Password
字段中输入值时,此代码的问题才可见。通知视图显示正确,但同时
用户名
密码
字段的值正在丢失

发生这种情况是因为整个视图树正在重新渲染,通过
NavigationLink
创建一个全新的
LoginView
实例,其中包含一个空的
LoginModel

如何在SwiftUI中正确执行此操作,以使值不会丢失

导入快捷界面
最终类通知模型:ObserveObject{
func show(文本:字符串){
self.text=文本
isHidden=false
}
@出版
var isHidden=true
var text=“”
}
结构通知视图:视图{
@环境对象
var模型:NotificationModel
var body:一些观点{
GeometryReader{中的几何体
如果!self.model.ishiden{
团体{
HStack{
图像(系统名:“感叹号标记.三角形”)
.font(font.largeTitle.weight(.light))
文本(self.model.Text)
.font(font.body.weight(.medium))
.padding()
垫片()
}
.frame(最大宽度:。无穷大,最小高度:geometry.safeareainsetts.top+44)
.填充(边设置(顶部:几何体。安全区域插入。顶部,前导:20,底部:0,尾随:20))
}
.背景(颜色.红色)
.transition(AnyTransition.move(边:。顶部)。与:。不透明度组合)
.ontapsigne{
动画片{
self.model.ishiden=true
}
}
}
}.edgesIgnoringSafeArea(.all)
}
}
最终类LoginModel:ObserveObject{
@出版
var email=“”
@出版
var password=“”
let notificationModel:notificationModel
init(notificationModel:notificationModel){
self.notificationModel=notificationModel
}
func submit(){
notificationModel.show(文本:“用户名/密码错误”)
}
}
结构逻辑视图:视图{
@观察对象
var模型:LoginModel
var body:一些观点{
VStack{
文本字段(“用户名”,文本:$model.email)
分隔器()
文本字段(“密码”,文本:$model.Password)
分隔器()
按钮(操作:{
self.model.submit()
}) {
文本(“提交”)
}
}
}
}
结构ContentView:View{
@环境对象
var notificationModel:notificationModel
var body:一些观点{
ZStack{
导航视图{
VStack{
导航链接(目标:LoginView(模型:LoginModel(notificationModel:notificationModel))){
文本(“登录”)
}
垫片()
}
.navigationBarTitle(“开始”)
}
通知视图()
}
}
}

您可能需要在contentView中翻转LoginModel和notificationModel

            final class NotificationModel: ObservableObject {
                func show(text: String) {
                    self.text = text
                    self.isHidden = false
                }

                @Published
                var isHidden = true
                var text = ""
            }

            struct NotificationView: View {
                @EnvironmentObject
                var model: NotificationModel

                var body: some View {
                    GeometryReader { geometry in
                        if !self.model.isHidden {
                            Group {
                                HStack {
                                    Image(systemName: "exclamationmark.triangle")
                                        .font(Font.largeTitle.weight(.light))
                                    Text(self.model.text)
                                        .font(Font.body.weight(.medium))
                                        .padding()
                                    Spacer()
                                }
                                .frame(maxWidth: .infinity, minHeight: geometry.safeAreaInsets.top + 44)
                                .padding(EdgeInsets(top: geometry.safeAreaInsets.top, leading: 20, bottom: 0, trailing: 20))
                            }
                            .background(Color.red)
                            .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
                            .onTapGesture {
                                withAnimation {
                                    self.model.isHidden = true
                                }
                            }
                        }
                    }.edgesIgnoringSafeArea(.all)
                }

            }

            final class LoginModel: ObservableObject {
                @Published
                var email = ""

                @Published
                var password = ""



                let notificationModel: NotificationModel

                init(notificationModel: NotificationModel) {
                    self.notificationModel = notificationModel
                }

                func submit() {
                    notificationModel.show(text: "Username/password wrong")
                }
            }

            struct LoginView: View {
                @ObservedObject
                var model: LoginModel

                var body: some View {
                    VStack {
                        TextField("Username", text: $model.email)
                        Divider()
                        TextField("Password", text: $model.password)
                        Divider()
                        Button(action: {
                            self.model.submit()
                        }) {
                            Text("Submit")
                        }
                    }
                }
            }

            struct ContentView: View {
                @EnvironmentObject  var loginModel : LoginModel

                var body: some View {




                  return  ZStack {
                        NavigationView {
                            VStack {
                                NavigationLink(destination: LoginView(model: loginModel)) {
                                    Text("Login")
                                }
                                Spacer()
                            }
                            .navigationBarTitle("Start")
                        }
                    NotificationView().environmentObject(loginModel.notificationModel)
                    }
                }
            }

谢谢,但这不是一个真正的选择。假设有另一组嵌套视图(选项卡栏等),表示应用程序的登录部分。问题是一样的,我不想让最外层的视图保存最内层的模型。每个登录模型或中间视图模型都应该有自己的通知模式。没有全局通知模型