SwiftUI搭配Firebase开发时用户登出后Navigation Bar仍保留如何解决
问题1:登出后导航栏叠加显示
成因
你将NavigationView放在了ContentView的最外层,作为登录/注册页和首页的公共容器,所有导航栏配置(标题、按钮、显隐)都会作用在这个全局的NavigationView上。FirstView中设置的导航栏标题、按钮等属性,不会在页面切换到登录页时自动清空,同时SignInView也没有主动配置导航栏隐藏,因此会出现导航栏残留叠加的问题,和FirstView是否正确关闭无关。
解决方案
推荐将NavigationView的作用域限制在登录后的页面,修改ContentView代码如下:
struct ContentView: View { @EnvironmentObject var viewModel: AppViewModel var body: some View { Group { // 移除外层公共的NavigationView if viewModel.signedIn { // 仅给登录后的页面套NavigationView NavigationView { FirstView() } } else { SignInView() .onAppear(perform: UIApplication.shared.addTapGestureRecognizer) // 若仍保留公共NavigationView,可加这行隐藏登录页导航栏 // .navigationBarHidden(true) } } .onAppear { viewModel.listen() } } }
登出时signedIn变为false,包含NavigationView的首页节点会被整体移除,自然不会残留导航栏。如果需要兼容旧的布局逻辑,也可以直接给SignInView添加.navigationBarHidden(true)修饰符强制隐藏导航栏。
问题2:FirstView用户数据更新延迟
成因
有两个核心原因:
- 登录状态校验通过后你立刻将
signedIn设为true跳转到首页,此时Firestore的用户数据异步请求还未返回,FirstView会先显示占位的默认文本,等请求返回才更新,视觉上存在明显切换滞后。 - Firestore的
getDocument回调默认执行在后台线程,你在回调中直接给@Published属性userInfo赋值,非主线程更新发布属性会导致UI更新被系统延迟调度,进一步加重卡顿感。
解决方案
修改AppViewModel中的fetchUserData和listen方法:
func fetchUserData(completion: @escaping () -> Void = {}){ db.collection("Users").document("\(userIdRef)").getDocument { document, error in guard error == nil, let document = document, document.exists else { completion() return } let user = document.map { documentSnapshot -> User in let data = documentSnapshot.data() let uid = data?["uid"] as? UUID ?? UUID() let company = data?["company"] as? String ?? "" let name = data?["name"] as? String ?? "" let admin = data?["admin"] as? Bool ?? false let photo = data?["photo"] as? String ?? "" return User(uid: uid, company: company, name: name, admin: admin, photo: photo) } // 切主线程更新发布属性 DispatchQueue.main.async { self.userInfo = user completion() } } } func listen(){ handle = authRef.addStateDidChangeListener({ auth, user in print(user?.email ?? "No User Found") if let user = auth.currentUser { self.userIdRef = user.uid self.rootInfoCollection = Firestore.firestore().collection("/Users/") // 拉取到用户数据后再跳转首页,消除占位文本切换的感知 self.fetchUserData { DispatchQueue.main.async { self.signedIn = true } } } else { DispatchQueue.main.async { self.signedIn = false // 登出时清空用户数据,避免下次登录闪现旧数据 self.userInfo = nil } } }) }
如果不想在登录时增加等待时间,也可以保留原有的跳转逻辑,只需给userInfo的赋值加上主线程调度即可消除额外的更新延迟。
内容的提问来源于stack exchange,提问作者RapsIn4
相关产品推荐
相关产品推荐

