使用 SwiftUI 成功登录后导航 [英] Navigate after successful login with SwiftUI

查看:44
本文介绍了使用 SwiftUI 成功登录后导航的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

导入 SwiftUI结构内容视图:查看{@StateObject var userLoggedIn = LoginViewModel()var主体:一些视图{如果 !userLoggedIn.isLoggedIn {登录视图()}别的 {主视图()}}}

登录视图:

导入 SwiftUI导入 FirebaseAuth结构登录视图:查看{@State private var email: String = "";@State 私有变量密码:String = "";@State 私有变量 isEditing = false@State 私有 var showPassword = false@State 私有变量半径 = 300私有变量 canLogIn: Bool {返回 !email.isEmpty &&!password.isEmpty}让 loginView = LoginViewModel()@ViewBuildervar主体:一些视图{返回导航视图(内容:{虚拟堆栈{垫片().frame(高度:150)文本(宠物支持").前景颜色(Color.petSupportText).font(Font.custom(永久标记",大小:36)).填充()团体 {堆栈{文本(电子邮件").font(Font.custom(永久标记",大小:18)).padding(.top, 10)垫片()}文本字段(电子邮件",文本:$email){self.isEditing = isEditing 中的 isEditing}.autocapitalization(.none).keyboardType(.emailAddress).disableAutocorrection(true).padding(.top, 20)分隔线().foregroundColor(.black)}团体 {堆栈{文本(密码").font(Font.custom(永久标记",大小:18)).padding(.top, 10)垫片()}ZStack {如果显示密码{文本字段(密码",文本:$密码)}别的 {SecureField(密码",文本:$password)}}.frame(高度:20).autocapitalization(.none).overlay(Image(systemName: showPassword ? eye.slash": eye").onTapGesture { showPassword.toggle() }, 对齐方式:.trailing).disableAutocorrection(true).padding(.top, 20)分隔线().foregroundColor(.black)}间隔();团体 {按钮(动作:{loginView.login(电子邮件:电子邮件,密码:密码)半径 = 2000主视图()}, 标签: {文本(登录")}).foregroundColor(.white).font(Font.custom(永久标记",大小:18.0)).padding(.horizo​​ntal, 20).填充().background(Color.petSupportBlue).cornerRadius(70.0).disabled(!canLogIn)}垫片()}.padding(.horizo​​ntal, 30).ignoresSafeArea()})}}

登录视图模型:

导入基础导入 Firebase类 LoginViewModel:ObservableObject {@Published var isLoggedIn = falsefunc 登录(电子邮件:字符串,密码:字符串){Auth.auth().signIn(withEmail: email, password: password) { (result, error) in如果让错误 = 错误 {打印(错误.本地化描述)} 别的 {打印(登录!")self.isLoggedIn = 真}}}}

主视图:

导入 SwiftUI结构主视图:查看{var主体:一些视图{文本(你好,世界!")}}

解决方案

如果不想处理NavigationLink,如@Paulw11 在评论中提到的,可以有条件地显示一个已登录/logged out view 基于您在 ObservableObject 上设置的属性.您甚至可以添加动画/过渡.下面是一个简单的例子:

<预><代码>类登录管理器:ObservableObject {@Published var isLoggedIn = false功能登录(){DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {带动画{self.isLoggedIn = 真}}}}结构内容视图:查看{@StateObject var loginManager = LoginManager()var主体:一些视图{如果 loginManager.isLoggedIn {登录视图().frame(maxWidth: .infinity, maxHeight: .infinity).transition(.move(edge: .leading))} 别的 {登录视图(登录管理器:登录管理器).frame(maxWidth: .infinity, maxHeight: .infinity).transition(.move(edge: .leading))}}}结构登录视图:查看{@ObservedObject var loginManager : LoginManagervar主体:一些视图{按钮(登录"){loginManager.login()}}}struct LoggedInView:查看{var主体:一些视图{文本(已登录!")}}

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

I'm using Firebase and SwiftUI to log in as a user. 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. The LoginView contains the login screen and the LoginViewModel does the sign-in procedure with 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 (i.e if I navigate to the Login view, it won't go to the main view after the login button is pressed).

ContentView (The root view displaying all the other views):

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. 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. 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.

这篇关于使用 SwiftUI 成功登录后导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆