Home > database >  How to perform action before executing navigationLink
How to perform action before executing navigationLink

Time:10-05

I am building and app and I am currently in the Login view. In this view, the user enters its information and then clicks a "Log In" button. The thing is that I need to make some calls to my API when the user clicks the button, and then execute the NavigationLink method, if the data the user entered was correct. The only way I have managed to to this has been using isActive parameter, but it is no longer available as it is deprecated.

My code currently is the following:

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

I have also tried with NavigationStack, but it doesn't work either.

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

CodePudding user response:

Instead of using a navigation link use a button and have a separate navigation link which can be activate by an @State variable. I've added a fake login method that disables the button and shows an activity indicator while the login process in occurring.

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

Sorry I haven't updated to the latest swiftui but after doing some research you can use navigationDestination(isPresented:

struct ContentView: View {

  @State var isPresentedDetailView = false

  var body: some View {

    NavigationStack {
        VStack {
          Text("Name")
            .onTapGesture {
              isPresentedDetailView.toggle()
            }

      }
      .navigationDestination(isPresented: $isPresentedImageView) {
        Image(systemName: "person")
      }
    }
  }
}
  • Related