简体   繁体   中英

How do I switch views when the timer ends SwiftUI

I have two views. The Main View and a Break View. I have a timer running in the Main View which counts down to zero. When the timer reaches zero, I want to be able to switch the screen to Break View. I am using MVVM to keep track of the timers. Using.onReceive to make it look like the timer is running in the background.

I tried using a boolean to check if the timer has reached zero and based on that changed the view, but it's not working and is giving an error saying the result of the view is not used anywhere. I have a navigation view in the Content View if that's of any help.

Thanks in advance.

A snippet of the code:

Main View:

struct MainView: View {

    var body: some View {
       
                VStack(alignment: .center, spacing: 50, content: {

                        Button(action: {
                            if !fbManager.isTimerStarted {
                                fbManager.start()
                                fbManager.isTimerStarted = true
                            }
                            else {
                                 fbManager.pause()
                                 fbManager.isTimerStarted = false
                            }
                            
                        }, label: {
                            Image(systemName: fbManager.isTimerStarted == true ? "pause.fill" : "play.fill")
                                .resizable()
                                .scaledToFit()
                                .frame(width: 50, height: 50)
                                .foregroundColor(Color(red: 1.00, green: 1.00, blue: 1.00))
                        })
                        .onReceive(NotificationCenter.default.publisher(
                            for: UIScene.didEnterBackgroundNotification)) { _ in
                                if fbManager.isTimerStarted {
                                    movingToBackground()
                                }
                                
                        }
                            .onReceive(NotificationCenter.default.publisher(
                                for: UIScene.willEnterForegroundNotification)) { _ in
                                    
                                    if fbManager.isTimerStarted {
                                        movingToForeground()
                                    }
                                    
                                }
                })
        }
    }
    
    func movingToBackground() {
        print("Moving to the background")
        notificationDate = Date()
        fbManager.pause()
    }
    
    func movingToForeground() {
        
        print("Moving to the foreground")
        
        let deltaTime: Int = Int(Date().timeIntervalSince(notificationDate))
        fbManager.secondsElapsed -= deltaTime
        fbManager.start()
    }
    
}

View Model:

class FocusBreakManager: ObservableObject {
  
    var timer: Timer = Timer()

    func start() {
        
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [self] _ in
            
            self.secondsElapsed -= 1
            self.focusfill += 0.01667
            focusTime = String(secondsElapsed)
            focusTime = formatCounter()
            
            if secondsElapsed <= 0 {
                
                stop()

            }

        }
    }
 
    func formatCounter() -> String {
        
        let minutes = Int(secondsElapsed) / 60 % 60
        let seconds = Int(secondsElapsed) % 60
        return String(format : "%02i : %02i", minutes, seconds)
    }
    
}

Hey to keep up with your solution here is an example of how that could work you would need to use @ObservedObject property wrapper in order to monitor updates from your view.

struct ContentView: View {

    @ObservedObject private var focusBreakManager = FocusBreakManager()

    var body: some View {
        VStack {
            Text("\(focusBreakManager.elapsedSeconds)")
            Text(focusBreakManager.timerRunningMessage)
            Button("Start timer", action: focusBreakManager.start)
        }
        .padding()
    }
}

class FocusBreakManager: ObservableObject {

    var timer: Timer = Timer()
    @Published var elapsedSeconds = 0

    var timerRunningMessage: String {
        timerRunning
        ? "Timer is running"
        : "Timer paused"
    }

    private var timerRunning: Bool {
        timer.isValid
    }

    func start() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            guard let self else { return }
            self.elapsedSeconds += 1
            if self.elapsedSeconds > 5 {
                self.timer.invalidate()
            }
        }
    }

}

You can also take a look at the autoconnect api here's a great tutorial: https://www.hackingwithswift.com/books/ios-swiftui/triggering-events-repeatedly-using-a-timer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM