I'm fairly new to SwiftUI and I ran into this issue trying to figure out how to work with Environment object in many views.
I'm trying to move to the next view after successful login which is happening, I'm then updating @Published Isloggedin
to true, which all is fine up until now.
I'm also wondering if my approach is good or if should I change to a completely different approach.
Here is my LoginView that contains nested structs in them and this is exactly my issue, I don't know how to pass the same Env object to child views.
[Edited] : I made some changes and the navigation works now but it lags a bit, it takes few seconds because it navigates to the next page so I'm wondering now if I'm doing anything wrong that's causing the navigation to lag.
struct LoginView: View {
var body: some View {
VStack(alignment: .center){
//
cardView(image: "LoginImg", title: "Title here ", subtitle: "subtitle here")
Spacer()
}.background(Color("PrimaryColor"))
}
}
Here is the code with my CardView :
struct cardView: View
{
@State private var isShowingWebView: Bool = false
var body: some View {
VStack(spacing: 30){
ZStack{
//
VStack(spacing: 12){
ContinueWithGoogleBtn(image: "GoogleLogo", text: "Continue with Google")
ContinueWithDropboxBtn(image: "DropboxLogo", text: "Continue with Dropbox")
ContinueWithMicrosoftBtn(image: "MicrosoftLogo", text: "Continue with Microsoft")
}
//
}
}
Then my GoogleButton
struct ContinueWithGoogleBtn: View{
var image: String
var text: String
@EnvironmentObject var vm: userAuthModelGoogle()
var body: some View{
Button {
//userAuth.SigninwithGoogle()
vm.SigninwithGoogle()
} label: {
//
}
}
}
ContentView :
struct ContentView: View {
@StateObject var userAuth = userAuthModelGoogle()
var body: some View {
NavigationView{
if userAuth.isLoggedin {
HomeScreen(isshowing: false)
}
else {
LoginView()
}
}.environmentObject(userAuth)
.navigationBarTitle("")
.navigationBarHidden(true)
}
and on my main file I'm just the contentstruct
@main
struct testapp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Thank you in advance
You don't need to/should not use nested structs. Otherwise your approach is good. A simplified version runs fine with me.
The only mistake seems to be in ContinueWithGoogleBtn
:
@EnvironmentObject var vm: userAuthModelGoogle()
should be:
@EnvironmentObject var vm: userAuthModelGoogle
Skip the () – you don't want to instantiate an object, but get the one from the environment that matches the type.
For reference here is my full code that works well:
struct LoginView: View {
var body: some View {
VStack(alignment: .center) {
//
cardView()
Spacer()
}
}
}
struct cardView: View {
@State private var isShowingWebView: Bool = false
var body: some View {
VStack(spacing: 30){
ZStack{
//
VStack(spacing: 12){
ContinueWithGoogleBtn(image: "GoogleLogo", text: "Continue with Google")
// ContinueWithDropboxBtn(image: "DropboxLogo", text: "Continue with Dropbox")
// ContinueWithMicrosoftBtn(image: "MicrosoftLogo", text: "Continue with Microsoft")
}
//
}
}
}
}
struct ContinueWithGoogleBtn: View{
var image: String
var text: String
@EnvironmentObject var vm: userAuthModelGoogle
var body: some View{
Button {
//userAuth.SigninwithGoogle()
vm.SigninwithGoogle()
} label: {
//
Text(text)
}
}
}
// dummy
class userAuthModelGoogle: ObservableObject {
@Published var isLoggedin = false
func SigninwithGoogle() {
isLoggedin = true
}
}
struct ContentView: View {
@StateObject var userAuth = userAuthModelGoogle()
var body: some View {
NavigationView {
if userAuth.isLoggedin {
Text("HomeScreen")
}
else {
LoginView()
}
}
.environmentObject(userAuth)
.navigationBarTitle("")
.navigationBarHidden(true)
}
}