【问题标题】:SwiftUI - Form with error message on button press and navigationSwiftUI - 在按钮按下和导航时出现错误消息的表单
【发布时间】:2019-08-25 11:17:15
【问题描述】:

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

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

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

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

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

    首先,我将所有内容都移到了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),您将再次被发送回第二个视图。

    您没有发布有关第二个视图内容的任何详细信息,因此我冒昧地将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

    【讨论】:

    • 感谢您的详细解答。隐藏的导航链接正是我要寻找的。​​span>
    【解决方案2】:

    另一种方法是当 fieldValue 为空时有条件地使“Next”按钮成为 Button,当 fieldValue 有效时使 NavigationLink 成为条件。 Button case 将触发您的错误消息视图,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"))
                    }
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      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")))
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-11-04
        • 1970-01-01
        • 2014-01-21
        • 2021-09-14
        • 2020-03-03
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多