SwiftUI - How to Make A Start/Stop Timer

大兔子大兔子 提交于 2021-02-08 02:09:30

问题


My goal is to create a view in SwiftUI that starts with 0. When you press the view, a timer should start counting upwards, and tapping again stops the timer. Finally, when you tap again to start the timer, the timer should begin at 0.

Here is my current code:

import SwiftUI

struct TimerView: View {
    @State var isTimerRunning = false
    @State private var endTime = Date()
    @State private var startTime =  Date()
    let timer = Timer.publish(every: 0.001, on: .main, in: .common).autoconnect()
    
    var tap: some Gesture {
        TapGesture(count: 1)
            .onEnded({
                isTimerRunning.toggle()
            })
    }

    var body: some View {

        Text("\(endTime.timeIntervalSince1970 - startTime.timeIntervalSince1970)")
            .font(.largeTitle)
            .gesture(tap)
            .onReceive(timer) { input in
                startTime = isTimerRunning ? startTime : Date()
                endTime = isTimerRunning ? input : endTime
            }

    }
}

This code causes the timer to start instantly and never stop, even when I tap on it. The timer also goes backward (into negative numbers) rather than forward.

Can someone please help me understand what I am doing wrong? Also, I would like to know if this is a good overall strategy for a timer (using Timer.publish).

Thank you!


回答1:


Here is a fixed version. Take a look at the changes I made.

  • .onReceive now updates a timerString if the timer is running. The timeString is the interval between now (ie. Date()) and the startTime.
  • Tapping on the timer sets the startTime if it isn't running.

struct TimerView: View {
    @State var isTimerRunning = false
    @State private var startTime =  Date()
    @State private var timerString = "0.00"
    let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()

    var body: some View {

        Text(self.timerString)
            .font(Font.system(.largeTitle, design: .monospaced))
            .onReceive(timer) { _ in
                if self.isTimerRunning {
                    timerString = String(format: "%.2f", (Date().timeIntervalSince( self.startTime)))
                }
            }
            .onTapGesture {
                if !isTimerRunning {
                    timerString = "0.00"
                    startTime = Date()
                }
                isTimerRunning.toggle()
            }
    }
}

The above version, while simple, bugs me that the Timer is publishing all the time. We only need the Timer publishing when the timer is running.

Here is a version that starts and stops the Timer:

struct TimerView: View {
    @State var isTimerRunning = false
    @State private var startTime =  Date()
    @State private var timerString = "0.00"
    @State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {

        Text(self.timerString)
            .font(Font.system(.largeTitle, design: .monospaced))
            .onReceive(timer) { _ in
                if self.isTimerRunning {
                    timerString = String(format: "%.2f", (Date().timeIntervalSince( self.startTime)))
                }
            }
            .onTapGesture {
                if isTimerRunning {
                    // stop UI updates
                    self.stopTimer()
                } else {
                    timerString = "0.00"
                    startTime = Date()
                    // start UI updates
                    self.startTimer()
                }
                isTimerRunning.toggle()
            }
            .onAppear() {
                // no need for UI updates at startup
                self.stopTimer()
            }
    }
    
    func stopTimer() {
        self.timer.upstream.connect().cancel()
    }
    
    func startTimer() {
        self.timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
    }
}


来源:https://stackoverflow.com/questions/63548432/swiftui-how-to-make-a-start-stop-timer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!