简体   繁体   English

使用 SwiftUI 成功登录后导航

[英]Navigate after successful login with SwiftUI

I'm using Firebase and SwiftUI to log in as a user.我正在使用 Firebase 和 SwiftUI 以用户身份登录。 I have everything working but can't figure out how to navigate to the next page once the user is successfully logged in. NavigationLinks seem weird to me so I'm wondering if there's any other way to navigate to the next view.我一切正常,但不知道如何在用户成功登录后导航到下一页。NavigationLinks 对我来说似乎很奇怪,所以我想知道是否还有其他方法可以导航到下一个视图。 The LoginView contains the login screen and the LoginViewModel does the sign-in procedure with Firebase. LoginView包含登录屏幕, LoginViewModel使用 Firebase 执行登录过程。 The issue is that if I return views based on a variable in the root view, it doesn't change the view once any view other than the root view is opened (ie if I navigate to the Login view, it won't go to the main view after the login button is pressed).问题是,如果我基于根视图中的变量返回视图,一旦打开根视图以外的任何视图,它就不会更改视图(即,如果我导航到登录视图,它不会 go 到按下登录按钮后的主视图)。

ContentView (The root view displaying all the other views): ContentView(显示所有其他视图的根视图):

import SwiftUI

struct ContentView: View {
    @StateObject var userLoggedIn = LoginViewModel()
    var body: some View {
        if !userLoggedIn.isLoggedIn {
            LoginView()
        }
        else {
            MainView()
        }
    }
}

LoginView:登录视图:

import SwiftUI
import FirebaseAuth

struct LoginView: View {
    
    @State private var email: String = ""
    @State private var password: String = ""
    @State private var isEditing = false
    @State private var showPassword = false
    @State private var radius = 300
    
    private var canLogIn: Bool {
        return !email.isEmpty && !password.isEmpty
    }

    let loginView = LoginViewModel()
    
    @ViewBuilder
    var body: some View {
        
        return NavigationView(content: {
            
            VStack {
                Spacer()
                    .frame(height: 150)
                
                Text("PET SUPPORT").foregroundColor(Color.petSupportText)
                    .font(Font.custom("Permanent Marker", size: 36))
                    .padding()

                Group {
                    
                    HStack {
                        
                        Text("EMAIL")
                            .font(Font.custom("Permanent Marker", size: 18))
                            .padding(.top, 10)
                        
                        Spacer()
                        
                    }
                    
                    TextField("Email", text: $email) {
                        isEditing in self.isEditing = isEditing
                    }
                    .autocapitalization(.none)
                    .keyboardType(.emailAddress)
                    .disableAutocorrection(true)
                    .padding(.top, 20)
                    
                    Divider()
                        .foregroundColor(.black)
                    
                }

                
                Group {
                    
                    HStack {
                        
                        Text("PASSWORD")
                            .font(Font.custom("Permanent Marker", size: 18))
                            .padding(.top, 10)
                        
                        Spacer()
                        
                    }

                    ZStack {
                        if showPassword {
                            TextField("Password", text: $password)
                        }
                        else {
                            SecureField("Password", text: $password)
                        }
                    }
                    .frame(height: 20)
                    .autocapitalization(.none)
                    .overlay(Image(systemName: showPassword ? "eye.slash" : "eye").onTapGesture { showPassword.toggle() }, alignment: .trailing)
                    .disableAutocorrection(true)
                    .padding(.top, 20)
                    
                    Divider()
                        .foregroundColor(.black)
                    
                }
                
                Spacer();
                
                Group {
                    
                    Button(action: {
                            loginView.login(email: email, password: password)
                            radius = 2000
                            MainView()
                    }, label: {
                        Text("Login")
                    })
                        .foregroundColor(.white)
                        .font(Font.custom("Permanent Marker", size: 18.0))
                        .padding(.horizontal, 20)
                        .padding()
                        .background(Color.petSupportBlue)
                        .cornerRadius(70.0)
                        .disabled(!canLogIn)
                }
                
                Spacer()
            }
            .padding(.horizontal, 30)
            .ignoresSafeArea()
            
        })
        
    }
}

LoginViewModel:登录视图模型:

import Foundation
import Firebase

class LoginViewModel: ObservableObject {
    
    @Published var isLoggedIn = false
    func login(email: String, password: String) {
        
        Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
            
            if let error = error {
                print(error.localizedDescription)
            } else {
                print("Logged In!")
                self.isLoggedIn = true
            }
        }
        
    }
    
}

MainView:主视图:

import SwiftUI

struct MainView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

If you don't want to deal with NavigationLink , as @Paulw11 mentioned in the comments, you can conditionally display a logged in/logged out view based on a property you set on an ObservableObject .如果您不想处理NavigationLink ,正如评论中提到的@Paulw11 ,您可以根据您在ObservableObject上设置的属性有条件地显示登录/注销的视图。 You can even add animations/transitions.您甚至可以添加动画/过渡。 See below for a simple example:请参阅下面的简单示例:


class LoginManager : ObservableObject {
    @Published var isLoggedIn = false
    
    func login() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            withAnimation {
                self.isLoggedIn = true
            }
        }
    }
}

struct ContentView : View {
    @StateObject var loginManager = LoginManager()
    
    var body: some View {
        if loginManager.isLoggedIn {
            LoggedInView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .transition(.move(edge: .leading))
        } else {
            LoginView(loginManager: loginManager)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .transition(.move(edge: .leading))
        }
    }
}

struct LoginView : View {
    @ObservedObject var loginManager : LoginManager
    
    var body: some View {
        Button("Login") {
            loginManager.login()
        }
    }
}

struct LoggedInView : View {
    var body: some View {
        Text("Logged in!")
    }
}

I might also consider, if I were you, using at authStateListener and setting the logged in property based on that.如果我是你,我可能还会考虑使用 at authStateListener并基于此设置登录属性。 That way, if the app is re-opened and the user is still logged in, they'll be transitioned to the logged-in page automatically.这样,如果重新打开应用程序并且用户仍然登录,他们将自动转换到登录页面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM