SwiftUI - 如何制作启动/停止计时器

Posted

技术标签:

【中文标题】SwiftUI - 如何制作启动/停止计时器【英文标题】:SwiftUI - How to Make A Start/Stop Timer 【发布时间】:2020-08-23 14:58:32 【问题描述】:

我的目标是在 SwiftUI 中创建一个从 0 开始的视图。当您按下视图时,计时器应该开始向上计数,再次点击会停止计时器。最后,当您再次点击启动计时器时,计时器应从 0 开始。

这是我当前的代码:

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
            

    

此代码使计时器立即启动并且永不停止,即使我点击它也是如此。计时器也会向后(变为负数)而不是向前。

有人可以帮我理解我做错了什么吗?另外,我想知道这对于计时器来说是否是一个好的整体策略(使用 Timer.publish)。

谢谢!

【问题讨论】:

【参考方案1】:

这是一个固定版本。看看我所做的更改。

如果计时器正在运行,.onReceive 现在会更新 timerString。 timeString 是现在(即Date())和startTime 之间的间隔。 如果定时器没有运行,点击定时器会设置startTime
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()
            
    


上述版本虽然简单,但让我感到困扰的是Timer 一直在发布。我们只需要在计时器运行时发布Timer

这是一个启动和停止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()
    

【讨论】:

谢谢!这很好用。我刚刚开始学习 SwiftUI(和 Swift),这段代码已经帮助我掌握了一些概念。现在我只需要弄清楚如何使用我的 ContentView 中的时间 感谢 stopTimer 方法...

以上是关于SwiftUI - 如何制作启动/停止计时器的主要内容,如果未能解决你的问题,请参考以下文章

使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发

SwiftUI — 如何在 ScrollView 中显示倒计时?

如何停止和启动计时器?

如何在 ReactJS 中启动和停止计时器显示

SwiftUI:在设备方向上重绘会使计时器无效

使用计时器切换图像 (SwiftUI)