使用 SwiftUI 成功登录后导航

Posted

技术标签:

【中文标题】使用 SwiftUI 成功登录后导航【英文标题】:Navigate after successful login with SwiftUI 【发布时间】:2021-05-05 02:29:22 【问题描述】:

我正在使用 Firebase 和 SwiftUI 以用户身份登录。我一切正常,但不知道如何在用户成功登录后导航到下一页。NavigationLinks 对我来说似乎很奇怪,所以我想知道是否还有其他方法可以导航到下一个视图。 LoginView 包含登录屏幕,LoginViewModel 使用 Firebase 执行登录过程。问题是,如果我基于根视图中的变量返回视图,则一旦打开根视图以外的任何视图,它就不会更改视图(即,如果我导航到登录视图,它不会转到按下登录按钮后的主视图)。

ContentView(显示所有其他视图的根视图):

import SwiftUI

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

登录视图:

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

登录视图模型:

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
            
        
        
    
    

主视图:

import SwiftUI

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

【问题讨论】:

您应该在模型中创建某种“登录”状态,然后在您的根视图中,您可以根据该状态显示登录表单或登录视图。确保您的登录表单在用户成功登录后更新登录状态。 如果下一个视图是你的根视图,那么你可以试试这样, UIApplication.shared.keyWindow!.rootViewController = UIHostingController(rootView: ) 【参考方案1】:

如果您不想处理NavigationLink,正如cmets 中提到的@Paulw11,您可以根据您在ObservableObject 上设置的属性有条件地显示登录/注销视图。您甚至可以添加动画/过渡。下面是一个简单的例子:


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

如果我是你,我也可以考虑使用authStateListener 并基于此设置登录属性。这样,如果重新打开应用并且用户仍处于登录状态,他们将自动转换到登录页面。

【讨论】:

感谢您的回答!是的,我确实尝试过,但我遇到的问题是,如果我将所有视图作为单独的 SwiftUI 文件,例如,登录视图作为单独的文件。然后,如果我登录并单击登录按钮,它不会重定向。我已附上更新后的代码以显示这一点。 您正在创建新的/不同的 LoginViewModel 实例——您需要在视图之间传递相同的实例。看看我的例子是怎么发生的? 哦,拍!谢谢!现在我也更好地理解了 StateObject、ObservableObject 和 ObservedObject!

以上是关于使用 SwiftUI 成功登录后导航的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式导航到 SwiftUI 中的新视图

swiftUI:登录完成后导航到主屏幕。通过按钮单击导航视图

SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图

登录后如何在 SwiftUI 中显示新视图

成功登录后,SwiftUI ObservedObject 未更新视图

成功登录后 SwiftUI Firebase 身份验证关闭视图