如何构建一个按钮来单独控制计时器并在标签中显示倒计时?

Posted

技术标签:

【中文标题】如何构建一个按钮来单独控制计时器并在标签中显示倒计时?【英文标题】:How to build a button to control the timer individually and show the countdown in the label? 【发布时间】:2018-06-07 21:46:45 【问题描述】:

我 4 个月前刚刚学习了 Swift,我遇到了一个问题,但我不知道如何解决它。我看了很多关于 ***、Youtube 和 Medium 的教程,但我找不到合适的解决方案。

我的项目是:在ViewController中,有一个TableView,每个tableViewCell都有一个timerLabel、timerNameLabel、playButton和stopButton。当我单击 playButton 时,单元格的 timeLabel 将开始倒计时。当我单击停止按钮时,计时器将停止。

我知道如何构建正确的计时器和正确的 tableView:

视图控制器:

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 



    var myTimerList = CustomTimerList()

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() 
        super.viewDidLoad()

    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return myTimerList.timerList.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TimerTableViewCell
        return cell
    


TimerTableViewCell:

import UIKit

class TimerTableViewCell: UITableViewCell 

    var timer = Timer()

    @IBOutlet weak var timerName: UILabel!
    @IBOutlet weak var secondLeftLabel: UILabel!
    @IBAction func stopButton(_ sender: UIButton) 

        timer.invalidate()

    

    @IBAction func playButton(_ sender: UIButton) 

        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)

    

    @objc func updateTimer() 



    


定时器类:

import Foundation

class TimerClass 


    let timerSecond : Int
    let timerName : String

    init(second:Int, name:String) 


        timerSecond = second
        timerName = name

    


定时器列表:

import Foundation

class CustomTimerList 

    var timerList = [TimerClass]()

    init() 

        let customTimer = TimerClass(second: 100, name: "AAA")
        timerList.append(customTimer)
        timerList.append(TimerClass(second: 200, name: "BBB"))
        timerList.append(TimerClass(second: 400, name: "CCC"))
        timerList.append(TimerClass(second: 150, name: "DDD"))
        timerList.append(TimerClass(second: 800, name: "EEE"))
        timerList.append(TimerClass(second: 1000, name: "FFF"))

    


但我的问题是:

1.我尝试将 runTimer 放在 tableViewCell 中,并将我的 playButton 作为 IBAction 链接到 tableViewCell.swift。在这个按钮里面,是runTimer,但是我如何从TimerList 中获取数据并在timerLabel 中显示倒计时,因为我无法获得indexPath.row。

2.我尝试将runTimer放在viewController中,以便runTimer可以获取indexPath.row,但它还有另一个问题:如何在timerLabel上显示runTimer的结果并使其倒计时,因为timerLabel是链接在 tableViewCell 而不是 viewController。

我尝试了很多类似协议的方法,但我发现我无法正确处理协议,所以我不知道如何正确修改代码。

这里是原始文件:https://app.box.com/s/0xviuay00pa2ief8b94ar5oh1002q3tn

【问题讨论】:

参见this answer - 它处理的是向上计数,而不是向下计数,但这是一个简单的改变 此外,看看 CADisplayLink。以我的经验,它使计时器动画更流畅 【参考方案1】:

你需要设置cellForRowAt

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TimerTableViewCell

   let item = CustomTimerList.timerList[indexPath.row]
   cell.timerName.text = item.name
   cell.secondLeftLabel.text = "\(item.second)"

    return cell

//

struct CustomTimerList 

  static var timerList = [
      TimerClass(second: 100, name: "AAA"),
      TimerClass(second: 200, name: "BBB"),
      TimerClass(second: 400, name: "CCC"),
      TimerClass(second: 150, name: "DDD"),
      TimerClass(second: 800, name: "EEE"),
      TimerClass(second: 1000, name: "FFF")]


//

不要担心倒计时标签的当前内容并存储当前值,而是从它的文本中获取当前值,如果它不为零,则将其减小并将其设置回来,也不要认为您当前没有如果用户在cellForRowAt 中的这一行之后滚动,则计时器的停止机制

 let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TimerTableViewCell
 cell.timer?.invalidate()

//

class TimerTableViewCell: UITableViewCell 
    var timer:Timer?

【讨论】:

是的!!!!有用!!!!!汗,你救了我的命!!!!但我有最后一个问题,我发现当我滚动 tableview 时,计时器会停止!当我停止滚动时它会开始倒计时 我添加了这个:RunLoop.current.add(self.updateTimer, forMode: RunLoopMode.commonModes) 但xCode说:不能使用类型为'(() ->的参数列表调用'add' (), forMode: RunLoopMode)' 哦,我修复了它!再次感谢你!我会投票给你,但系统说我需要一些时间才能拥有“投票”功能。谢谢!!! 但是我发现,当我在滚动tableView的时候,正在运行的定时器从屏幕上滚了出来,我又往回滚动了,正在运行的定时器会被重置并停止……

以上是关于如何构建一个按钮来单独控制计时器并在标签中显示倒计时?的主要内容,如果未能解决你的问题,请参考以下文章

按下按钮后如何显示 24 小时计数器

24 小时倒计时计时器,带有三个单独的文本视图,分别显示小时、分钟、秒

Date应用计时器和倒计时

如何通过单击按钮启动倒数计时器事件?

JavaFX,标签setText中的倒数计时器

js实现倒计时