You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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用户数据更新延迟

成因

有两个核心原因:

  1. 登录状态校验通过后你立刻将signedIn设为true跳转到首页,此时Firestore的用户数据异步请求还未返回,FirstView会先显示占位的默认文本,等请求返回才更新,视觉上存在明显切换滞后。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:24:02