bhavesh chaudhari
bhavesh chaudhari

Reputation: 11

how to update envirment object without redraw entire View in SwiftUI

I am learning swiftUI. I have created a sample demo that contains 2 screens. first one is a splash screen and another is the login screen. In the splash screen, I used a timer with an interval of 5 seconds. when the count reaches 0 I want to redirect to the login screen.

the problem is Login screen redirecting multiple times.

here is starting Point

struct RoutingDemo_SwiftUIApp: App {
    
    @StateObject private var router = Router()
    
    var body: some Scene {
        WindowGroup {
            NavigationStack(path: $router.navPath) {
                SpashScreen().navigationDestination(for: Router.Destination.self, destination: { destination in
                    switch destination {
                    case .dashboardView:
                        TempView()
                    case .login:
                        LoginView().navigationTitle("")
                            .navigationBarBackButtonHidden()
                    }
                })
            }.environmentObject(router)
        }
    }
}

here is code of splash screen

struct SpashScreen: View {
    
    @EnvironmentObject var router: Router
   
    var body: some View {
        TimerView(callBack: {
            router.navigate(to: .login)
        })
        
    }
}

#Preview {
    SpashScreen()
}
struct TimerView: View {
    @State private var countDown = 5
    
    var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var callBack: (() -> Void)
    var body: some View {
        VStack {
            if let url = Bundle.main.url(forResource: "provider_splash", withExtension: "gif") {
                KFAnimatedImage(url).scaledToFill().frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height).ignoresSafeArea(.all)
            }
        }.onReceive(timer) { _ in
            if countDown > 0 {
                countDown -= 1
            } else {
                timer.upstream.connect().cancel()
                callBack()
            }
        }
    }
}

here is code of LoginView

struct LoginView: View {
   
    var body: some View {
        Button("Login", action: {
           
        })
    }
}

here is code of router

final class Router: ObservableObject {
    
    public enum Destination: Codable, Hashable {
        case login
        case dashboardView
    }
    
    @Published var navPath = NavigationPath()
    
    func navigate(to destination: Destination) {
        navPath.append(destination)
    }
    
    func navigateBack() {
        navPath.removeLast()
    }
    
    func navigateToRoot() {
        navPath.removeLast(navPath.count)
    }
}

I have tried to seperate timer view code from envirment object because updating envirment object cases swiftUI redraw entire view.

Upvotes: 1

Views: 60

Answers (1)

malhal
malhal

Reputation: 30746

Just remove the Router object and use multiple .navigationDestination for each type of thing you want to show.

Remove onReceive and use TimelineView for your counter.

Upvotes: 0

Related Questions