【问题标题】:Problem with SwiftUI programmatic navigationSwiftUI 程序化导航问题
【发布时间】:2021-07-04 15:04:50
【问题描述】:

我一直在尝试在我的 SwiftUI 代码中实现编程导航,但收效甚微。我打算为以下代码做的是检查用户是否填写了屏幕上的每个文本字段,如果是,则进入下一个屏幕。如果没有,则显示警报并允许用户返回并备份文本字段。然而,有一个障碍——如果用户在第一次尝试时完全填写了表单,他们可能会继续,但如果没有,他们会收到警报(如预期的那样),但是一旦他们再次填写表单完成,点击 NavigationLink 没有任何作用,而它应该允许用户转到下一个屏幕。

// this part of the code defines the validation logic
@State private var textFieldsInvalid = false
@State private var lineupIsReady = false

/// this is the navigation link i'm trying to fix
NavigationLink(destination: SetHomeLineup(), isActive: self.$lineupIsReady) {
                    HStack {
                        Spacer()
                        Label("Submit", systemImage: "chevron.right.circle.fill")
                        Spacer()
                    }
                    .padding(.all, 18)
                    .background(Color.green)
                    .foregroundColor(.white)
                    .font(.title)
                    .onTapGesture {
                        for name in checkIfFieldsValid {
                            if !(name.isEmpty) {
                                self.lineupIsReady = true
                            }
                            else {
                                self.textFieldsInvalid = true
                            }
                        }
                    }
                }
/* this is the alert modifier attached to a VStack that contains a Form 
(with its text fields) and the navigation link above. I haven't included the Form 
because it's too large and not the problem area for now. */

            }
            .edgesIgnoringSafeArea(.bottom)
            .alert(isPresented: $textFieldsInvalid, content: {
                Alert(title: Text("Incomplete Information"), message: Text("Please make sure that you have filled in all fields."), dismissButton: .default(Text("Back")))

就上下文而言,checkIfFieldsValid 是一个存储九名玩家姓名的数组(由用户输入文本字段并存储在@State private var 中)。我可以包含这些代码以及必要时的表单,但我相当确定它们不会参与错误,因为代码能够很好地读取和访问用户输入的名称。

谁能指出我的代码中导致错误的区域?我是初学者,只有两周的代码经验,所以任何帮助将不胜感激:)

【问题讨论】:

  • 我认为我有逻辑上的错误 -> 当用户未能填写文本字段并按下 NavLink 时,lineupIsReady 的状态变为 True。如果用户纠正了所有错误,再次填写并按下 lineupIsReady,那么显然不会发生任何事情,因为 True 状态保持不变。因此,当您在失败后向用户发出警报时,您应该在警报按钮中实现 lineupIsReady = false 。我希望这会有所帮助。
  • 是的,就是这样。谢谢!

标签: swift swiftui


【解决方案1】:

如果你删除这一行:

self.textFieldsInvalid = true

...然后,只要您的文本字段之一不为空,每次都会出现NavigationLink。这是因为您从未将 lineupIsReady 设置为 false。

for name in checkIfFieldsValid {
    if !(name.isEmpty) {
        self.lineupIsReady = true /// as long as one of the names aren't empty, you set it to true
    } else {
//        self.textFieldsInvalid = true (this line deleted for now)
    }
}

即使您的所有文本字段都为空,除了一个,lineupIsReady 仍将设置为 true,并且您的 NavigationLink 将触发。

您不能在循环中设置lineupIsReady,因为您需要遍历所有文本字段才能确定整个内容是否有效。相反,您需要在循环结束后设置它

var lineupReady = true /// by default, set it to true
for name in checkIfFieldsValid {
    if name.isEmpty {
        lineupReady = false /// if just 1 text field is empty, set `lineupReady` to false
        break /// you can exit the loop now, because there's no way `lineupReady` can be set to true again
    }
}
self.lineupIsReady = lineupReady /// will trigger the NavigationLink

好的,这是 1 个问题。现在警报呢?让我们再看看你的旧代码:

for name in checkIfFieldsValid {
    if !(name.isEmpty) {
        self.lineupIsReady = true
    } else {
        self.textFieldsInvalid = true /// triggers the alert
    }
}

当文本字段为空时,self.textFieldsInvalid = true 行会显示警报...这可能是多次。该警报还会中断NavigationLink,这就是它没有出现的原因。您也应该只在循环结束后设置一次。

/// add this after `self.lineupIsReady = lineupReady`
... 

if !lineupReady {
    textFieldsInvalid = true /// will trigger the alert
}

完整代码:

struct ContentView: View {
    @State private var textFieldsInvalid = false /// for the alert
    @State private var lineupIsReady = false /// for the NavigationLink
    @State private var checkIfFieldsValid = ["Text", "", "More text"]
    
    var body: some View {
        NavigationView {
            VStack {
                ForEach(checkIfFieldsValid.indices, id: \.self) { index in
                    TextField("", text: $checkIfFieldsValid[index])
                        .border(Color.blue)
                }
                
                NavigationLink(destination: Text("Home lineup"), isActive: self.$lineupIsReady) {
                    HStack {
                        Spacer()
                        Label("Submit", systemImage: "chevron.right.circle.fill")
                        Spacer()
                    }
                    .padding(.all, 18)
                    .background(Color.green)
                    .foregroundColor(.white)
                    .font(.title)
                    .onTapGesture {
                        var lineupReady = true /// by default, set it to true
                        for name in checkIfFieldsValid {
                            if name.isEmpty {
                                lineupReady = false /// if just 1 text field is empty, set `lineupReady` to false
                                break /// you can exit the loop now, because there's no way `lineupReady` can be set to true again
                            }
                        }
                        self.lineupIsReady = lineupReady /// will trigger the NavigationLink
                        
                        if !lineupReady {
                            textFieldsInvalid = true /// will trigger the alert
                        }
                    }
                }
            }
        }
        .edgesIgnoringSafeArea(.bottom)
        .alert(isPresented: $textFieldsInvalid, content: {
            Alert(title: Text("Incomplete Information"), message: Text("Please make sure that you have filled in all fields."), dismissButton: .default(Text("Back")))
        })
    }
}

结果:

【讨论】:

  • 感谢您的回复!但是,我想指出 textFieldsInvalid 在代码中用于显示警报。记住这一点,我将如何编辑我的代码?
  • 感谢您的帮助!我会不时回来查看它是否有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-28
  • 1970-01-01
  • 2020-04-09
  • 2019-06-02
相关资源
最近更新 更多