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