swift - 如何在执行 navigationLink 之前执行操作

标签 swift swiftui navigation swiftui-navigationlink

我正在构建应用程序,并且当前位于登录 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 中,可以使用 NavigationStacknavigationDestination 来替换,如下所示。

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/

相关文章:

swiftui - 在 SwiftUI 中创建胶囊风格进度

iOS 如何在整个应用程序中更改导航项的 "Back"按钮的文本

mysql - 如何将导航下拉菜单表示为 Java 对象(对于 JPA)

macos - Swift NotificationCenter 无法解包 Optional.None

ios - 通用链接在 IOS 12.1 中不起作用?

swift - 升级到 Alamofire 5.x

ios自定义后退按钮(不在导航栏中)

ios - 如何观察对象对 Realm 数据库的计数

swiftui - 刷新 SwiftUI 列表

xcode - 针对目标 macOS 10.15 使用 Xcode 12 构建错误