SwiftUI登录视图跳转后自动返回问题求助
SwiftUI登录成功后自动返回登录页的问题修复
我用SwiftUI开发了登录视图,通过UserDefaults校验用户名和密码,验证通过后跳转至FirstView。但成功登录后会自动返回登录视图,仅重启应用后功能正常。尝试简化实现却不知该修改哪里,相关代码如下:
@main文件代码
@main struct demoApp: App { @StateObject var dataController = DataController.shared init() { UserDefaults.standard.register(defaults: [ "username": "test@test.com", "password": "demo", "logData": false ]) } let userInfo = UserDefaults.standard.bool(forKey: "logData") var body: some Scene { WindowGroup { ContentView(data: dataController) .environment(\.managedObjectContext, dataController.container.viewContext) } } }
初始登录页代码
struct LoginPage: View { @State var username: String = "" @State var password: String = "" let userData = UserDefaults.standard.string(forKey: "username") let userPassword = UserDefaults.standard.string(forKey: "password") @State var credStatus = false @State var showerroralert = false @ObservedObject var data: DataController var body: some View { NavigationStack { VStack { Text("Welcome") .font(.title) Image("carbg") .resizable() .cornerRadius(20) .frame(width: 150, height: 150) TextField("Username", text: $username) .padding() .cornerRadius(5.0) .padding(.bottom, 20) SecureField("Password", text: $password) .padding() .cornerRadius(5.0) .padding(.bottom, 20) Button("Login") { if (userData == username && userPassword == password) { credStatus = true UserDefaults.standard.set(true, forKey: "logData") } else { showerroralert = true } } .buttonStyle(.borderedProminent) .alert("Wrong data", isPresented: $showerroralert) { } } .navigationDestination(isPresented: $credStatus) { ContentView(data: data) } } } }
ContentView代码
struct ContentView: View { @ObservedObject var data: DataController @State var userInfo = UserDefaults.standard.bool(forKey: "logData") var body: some View { if userInfo { FirstView() } else { LoginPage(data: data) } } }
更新后的登录页代码
struct LoginPage: View { @State var usernameTemp: String = "" @State var passwordTemp: String = "" @State var credStatus = false @State var showerroralert = false @ObservedObject var data: DataController @AppStorage("username") var username: String = "test@demo.tech" @AppStorage("password") var password: String = "demo" @AppStorage("logData") var logData: Bool = false var body: some View { NavigationStack { VStack { Text("Welcome") .font(.title) Image("carbg") .resizable() .cornerRadius(20) .frame(width: 150, height: 150) TextField("Username", text: $usernameTemp) .padding() .cornerRadius(5.0) .padding(.bottom, 20) SecureField("Password", text: $passwordTemp) .padding() .cornerRadius(5.0) .padding(.bottom, 20) Button("Login") { if (usernameTemp == username && passwordTemp == password) { credStatus = true logData = true } else { showerroralert = true } } .buttonStyle(.borderedProminent) .alert("Wrong data", isPresented: $showerroralert) { } } .navigationDestination(isPresented: $credStatus) { ContentView(data: data) } } } }
问题原因及修复方案
核心问题
- ContentView的登录状态未实时监听:用
@State存储userInfo只会在视图初始化时读取一次UserDefaults的值,登录后更新logData不会触发ContentView刷新,导致视图仍停留在登录页。 - 跳转逻辑冲突:登录页既通过
navigationDestination跳转到ContentView,又设置logData标记登录状态,而ContentView本身会根据logData切换视图,导致导航栈出现循环,最终自动返回登录页。
具体修复步骤
1. 让ContentView实时监听登录状态
将ContentView中的@State var userInfo替换为@AppStorage("logData"),这样UserDefaults的值变化时会自动触发视图刷新:
struct ContentView: View { @ObservedObject var data: DataController @AppStorage("logData") var userInfo: Bool = false // 替换原@State变量 var body: some View { if userInfo { FirstView() } else { LoginPage(data: data) } } }
2. 简化登录页的跳转逻辑
登录成功后仅需设置logData为true,无需手动跳转,ContentView会自动切换到FirstView。同时移除登录页的NavigationStack:
struct LoginPage: View { @State var usernameTemp: String = "" @State var passwordTemp: String = "" @State var showerroralert = false @ObservedObject var data: DataController @AppStorage("username") var username: String = "test@demo.tech" @AppStorage("password") var password: String = "demo" @AppStorage("logData") var logData: Bool = false var body: some View { VStack { Text("Welcome") .font(.title) Image("carbg") .resizable() .cornerRadius(20) .frame(width: 150, height: 150) TextField("Username", text: $usernameTemp) .padding() .cornerRadius(5.0) .padding(.bottom, 20) SecureField("Password", text: $passwordTemp) .padding() .cornerRadius(5.0) .padding(.bottom, 20) Button("Login") { if usernameTemp == username && passwordTemp == password { logData = true // 仅设置登录状态,ContentView自动切换视图 } else { showerroralert = true } } .buttonStyle(.borderedProminent) .alert("账号或密码错误", isPresented: $showerroralert) { } } } }
3. 优化@main文件
移除@main中多余的userInfo变量,保持默认值注册逻辑即可:
@main struct demoApp: App { @StateObject var dataController = DataController.shared init() { UserDefaults.standard.register(defaults: [ "username": "test@test.com", "password": "demo", "logData": false ]) } var body: some Scene { WindowGroup { ContentView(data: dataController) .environment(\.managedObjectContext, dataController.container.viewContext) } } }
修复原理
@AppStorage是SwiftUI提供的与UserDefaults绑定的属性包装器,能自动监听键值变化并刷新视图,解决了@State无法实时更新的问题。- 让ContentView作为根视图统一管理登录状态和视图切换,避免手动跳转导致的导航栈循环,从根源上解决自动返回的问题。
内容的提问来源于stack exchange,提问作者multiverse
相关产品推荐
相关产品推荐

