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

问题描述 投票:0回答:1

我正在尝试实现一个可以显示在导航栏顶部的视图。我们将此视图称为NotificationView。从任何其他SwiftUI视图中,触发该视图应该很容易。例如在登录视图上,如果用户名和密码错误。

下面您将找到我到目前为止的代码。仅当您在UsernamePassword字段中输入一个值时,此代码的问题才变得可见。通知视图正确显示,但是UsernamePassword字段同时丢失了它们的值。

这是因为再次重新渲染了整个视图树,并通过LoginView创建了一个带有空LoginModel的全新NavigationLink实例。

您如何在SwiftUI中正确执行此操作,以免丢失值?

import SwiftUI

final class NotificationModel: ObservableObject {
    func show(text: String) {
        self.text = text
        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 notificationModel: NotificationModel

    var body: some View {
        ZStack {
            NavigationView {
                VStack {
                    NavigationLink(destination: LoginView(model: LoginModel(notificationModel: notificationModel))) {
                        Text("Login")
                    }
                    Spacer()
                }
                .navigationBarTitle("Start")
            }
            NotificationView()
        }
    }
}

simulator video

swiftui
1个回答
0
投票
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) } } }
© www.soinside.com 2019 - 2024. All rights reserved.