SwiftUI - 按下按钮和导航时带有错误消息的表单

SwiftUI - Form with error message on button press and navigation

我有以下场景。我有一个文本字段和一个按钮,我需要的是在字段为空的情况下显示一条错误消息,如果没有,则将用户导航到下一个屏幕。

我已经尝试通过使用字段值并在按下按钮时检查它是否为空来有条件地显示错误消息,但是,我不知道如何导航到下一个屏幕。

struct SomeView: View {

    @State var fieldValue = ""
    @State var showErrorMessage = false

    var body: some View {
        NavigationView {
            VStack {
                TextField("My Field", text: $fieldValue).textFieldStyle(RoundedBorderTextFieldStyle())

                if showErrorMessage {
                    Text("Error, please enter value")
                }

                Button(action: {
                    if self.fieldValue.isEmpty {
                        self.showErrorMessage = true
                    } else {
                        self.showErrorMessage = false
                        //How do I put navigation here, navigation link does not work, if I tap, nothing happens
                    }
                }) {
                    Text("Next")
                }
            }
        }
    }
}

使用 UIKit 会很容易,因为我可以使用 self.navigationController.pushViewController

感谢部分回答 ,这里有一些工作代码。

首先,我将所有内容都移到了 EnvronmentObject 中,以便更轻松地传递给您的第二个视图。我还添加了一个 second 切换变量:

class Model: ObservableObject {
    @Published var fieldValue = ""
    @Published var showErrorMessage = false
    @Published var showSecondView = false
}

接下来,更改 ContentView 中的两件事。我添加了一个隐藏的 NavigationLink(带有 isActive 参数)来实际触发推送,同时更改 Button 操作以执行本地函数:

struct ContentView: View {
    @EnvironmentObject var model: Model

    var body: some View {
        NavigationView {
            VStack {
                TextField("My Field", text: $model.fieldValue).textFieldStyle(RoundedBorderTextFieldStyle())
                NavigationLink(destination: SecondView(), isActive: $model.showSecondView) {
                    Text("NavLink")
                }.hidden()
                Button(action: {
                    self.checkForText()
                }) {
                    Text("Next")
                }
                .alert(isPresented: self.$model.showErrorMessage) {
                    Alert(title: Text("Error"), message: Text("Please enter some text!"), dismissButton: .default(Text("OK")))
                }
            }
        }
    }
    func checkForText() {
        if model.fieldValue.isEmpty {
            model.showErrorMessage.toggle()
        } else {
            model.showSecondView.toggle()
        }
    }
}

切换 showErrorMessage 将显示 Alert,切换 `showSecondView 将带您进入下一个视图。

最后,第二个观点:

struct SecondView: View {
    @EnvironmentObject var model: Model
    var body: some View {
        ZStack {
            Rectangle().fill(Color.green)
            // workaround
            .navigationBarBackButtonHidden(true) // not needed, but just in case
            .navigationBarItems(leading: MyBackButton(label: "Back!") {
                self.model.showSecondView = false
            })
            Text(model.fieldValue)
        }
    }
    func popSecondView() {
        model.showSecondView.toggle()
    }
}
struct MyBackButton: View {
    let label: String
    let closure: () -> ()

    var body: some View {
        Button(action: { self.closure() }) {
            HStack {
                Image(systemName: "chevron.left")
                Text(label)
            }
        }
    }
}

这就是上面链接的答案对我有帮助的地方。返回导航中似乎存在一个错误,该错误在 beta 6 中仍然存在。如果没有此解决方法(切换 showSecondView),您将再次返回到第二个视图。

你没有 post 第二个视图内容的任何细节,所以我冒昧地将 someText 添加到模型中以向你展示如何轻松地将东西传递到它可以使用一个 EnvironmentObject。在 SceneDelegate:

中执行此操作需要一点设置
var window: UIWindow?
var model = Model()

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    let contentView = ContentView()

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView.environmentObject(model))
        self.window = window
        window.makeKeyAndVisible()
    }
}

我注意到这方面有细微的变化,具体取决于您的项目创建时间(beta 6 声明了 contentView 的实例,而旧版本则没有)。无论哪种方式,声明一个 model 的实例,然后将 envoronmentObject 修饰符添加到 contentView.

另一种方法是在 fieldValue 为空时有条件地将 "Next" 按钮设为 Button,在 fieldValue 有效时设为 NavigationLink。 Button 案例将触发您的错误消息视图,而 NavigationLink 将为您进行导航。让这个接近您的样本,以下似乎可以解决问题。

struct SomeView: View {

    @State var fieldValue = ""
    @State var showErrorMessage = false

    var body: some View {
        NavigationView {
            VStack {
                TextField("My Field", text: $fieldValue).textFieldStyle(RoundedBorderTextFieldStyle())

                if showErrorMessage {
                    Text("Please Enter Data")
                }

                if fieldValue == "" {
                    Button(action: {
                        if self.fieldValue == "" {
                            self.showErrorMessage = true
                        }

                    }, label: {
                        Text("Next")
                    })
                } else {
                    // move on case
                    NavigationLink("Next", destination: Text("Next View"))
                }
            }
        }
    }
}

通过使用此代码,我们可以在字段为空时显示警报 else 。它会导航。

struct SomeView: View {

    @State var userName = ""
    @State var password = ""
    @State var showErrorMessage = false

    var body: some View {
        NavigationView {
            VStack {
                TextField("Enter Username", text: $userName).textFieldStyle(RoundedBorderTextFieldStyle())
                SecureField("Enter Your Password", text: $password)
                    .textFieldStyle(RoundedBorderTextFieldStyle())


                if userName == "" || password == "" {
                    Button(action: {
                        if self.userName == ""  || self.password == "" {
                            self.showErrorMessage = true
                        }
                   }, label: {
                        Text("Login")
                    })
                } else {
                    // move case
                    NavigationLink("Login", destination: Text("Login successful"))
                }
            }.alert(isPresented: $showErrorMessage) { () -> Alert in
                Alert(title: Text("Important Message"), message: Text("Please Fill all the Fields"), primaryButton: .default(Text("Ok")), secondaryButton: .destructive(Text("Cancel")))
            }
        }
    }
}