我正在构建应用程序,并且当前位于登录 View 中。在此 View 中,用户输入其信息,然后单击“登录”按钮。问题是,当用户单击按钮时,我需要对 API 进行一些调用,然后如果用户输入的数据正确,则执行 NavigationLink 方法。我设法做到这一点的唯一方法是使用 isActive 参数,但它不再可用,因为它已被弃用。
我目前的代码如下:
var body: some View {
NavigationView(){
GeometryReader { geometry in
VStack(alignment: .center, spacing: 24){
TextField("Enter your username", text: $username)
.font(.title3)
.frame(maxWidth: geometry.size.width*0.85)
.padding()
.background(Color.white.opacity(0.9))
.cornerRadius(22)
SecureField("Enter your password", text: $password)
.font(.title3)
.frame(maxWidth: geometry.size.width*0.85)
.padding()
.background(Color.white.opacity(0.9))
.cornerRadius(22)
Text("Log in")
.font(.title2)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
.background(Color.accent)
.cornerRadius(22)
.padding(.horizontal).onTapGesture {
buttonClicked()
// In the method buttonClicked I would like to make the API
// calls and then the navigate to main view
}
}
.frame(width: geometry.size.width)
.frame(minHeight: geometry.size.height)
.background(Color.welcomeBackground)
.navigationTitle("Log In")
}
}
.toolbar(.visible)
}
我也尝试过使用 NavigationStack,但它也不起作用。
@State private var signInPressed: Bool = false
var body: some View {
NavigationStack{
GeometryReader { geometry in
VStack(alignment: .center, spacing: 24){
TextField("Enter your username", text: $username)
.font(.title3)
.frame(maxWidth: geometry.size.width*0.85)
.padding()
.background(Color.white.opacity(0.9))
.cornerRadius(22)
SecureField("Enter your password", text: $password)
.font(.title3)
.frame(maxWidth: geometry.size.width*0.85)
.padding()
.background(Color.white.opacity(0.9))
.cornerRadius(22)
Text("Log in")
.font(.title2)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
.background(Color.accent)
.cornerRadius(22)
.padding(.horizontal).onTapGesture {
signInPressed.toggle()
}
}
.frame(width: geometry.size.width)
.frame(minHeight: geometry.size.height)
.background(Color.welcomeBackground)
.navigationTitle("Log In")
}
}
.navigationDestination(isPresented: $signInPressed, destination: {
ContentView()
})
.toolbar(.visible)
}
最佳答案
不要使用导航链接,而是使用按钮并拥有一个单独的导航链接,该链接可以通过 @State
变量激活。我添加了一个假登录方法,该方法会在登录过程发生时禁用按钮并显示事件指示器。
func Login() async -> Bool {
try? await Task.sleep(nanoseconds: 5 * 1_000_000_000) // 5 seconds
return true
}
struct LoginView : View {
@State private var showMainView = false
@State private var isLoggingIn = false
var body: some View {
NavigationView{
VStack{
NavigationLink(destination: Text("Logged in"), isActive: $showMainView) { EmptyView() }
Button(action: {
isLoggingIn = true
// do code to validate login here
Task {
//if login call worked then show the main view
showMainView = await Login()
isLoggingIn = false
}
})
{
HStack{
Spacer()
if(isLoggingIn){
ProgressView()
}
else{
Text("Login")
}
Spacer()
}.padding()
.background(.green)
}.disabled(isLoggingIn)
}
}
}
}
iOS 16:
在 iOS 16 中,可以使用 NavigationStack
和 navigationDestination
来替换,如下所示。
struct LoginView : View {
@State private var showMainView = false
@State private var isLoggingIn = false
var body: some View {
NavigationStack{
VStack{
Button(action: {
isLoggingIn = true
// do code to validate login here
Task {
//if login call worked then show the main view
showMainView = await Login()
isLoggingIn = false
}
})
{
HStack{
Spacer()
if(isLoggingIn){
ProgressView()
}
else{
Text("Login")
}
Spacer()
}.padding()
.background(.green)
}.disabled(isLoggingIn)
}.navigationDestination(isPresented: $showMainView) {
Text("Logged in")
}
}
}
}
关于swift - 如何在执行 navigationLink 之前执行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73939238/