2

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) } 
2
  • Have you tried .disabled()? hackingwithswift.com/quick-start/swiftui/… Commented Oct 3, 2022 at 19:40
  • The thing is that I don't want that to be disabled, I want to navigate to make an HTTP request, and depending of the response, navigate to another view. That would be useful to disable the button but that's not what I want. Commented Oct 3, 2022 at 19:51

1 Answer 1

3

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

< iOS 16:

 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:

In iOS 16 this can be replaced by using a NavigationStack and a navigationDestination as seen below.

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") } } } } 
Sign up to request clarification or add additional context in comments.

3 Comments

Exactly, the first solution is not available anymore in the last version of SwiftUI, and I've just tried the second one but it does not work either. It doesn't do anything. I have updated the initial question with the code you suggested, if you want to check it out.
Okay, my bad. I was calling navigationDestination outside NavigationStack. Now it's working correctly. Many thanks!
Finally!! I was looking for this answer everywhere

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.