在UICollectionViewCell中使用计时器添加倒计时标签的最佳方法,即使在重复使用单元格之后也能正常工作

时间:2017-10-22 08:00:37

标签: ios swift swift3 timer uicollectionviewcell

我有一个在UICollectionView中向用户展示的项目列表。这些项目具有倒计时标签,以显示该项目可用的剩余时间。 我在Timer中使用UICollectionViewCell来显示剩余时间,如:

OperationQueue.main.addOperation {
        var remaingTimeInterval = self.calculateRemainigTime(remainingTime: remainingTime)
        if remaingTimeInterval > 0 {
            self.timerLabel.isHidden = false
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in
                let hours = Int(remaingTimeInterval) / 3600
                let minutes = Int(remaingTimeInterval) / 60 % 60
                let seconds = Int(remaingTimeInterval) % 60
                self?.timerLabel?.text = String(format:"%02i:%02i:%02i", hours, minutes, seconds)
                remaingTimeInterval -= 1
            })
        } else {
            self.timer?.invalidate()
            self.timerLabel.isHidden = true
        }
    }

以及我如何根据给定日期计算剩余时间:

//Calculating remaining time based on the item endDate and currentDAte
    func calculateRemainigTime(remainingTime: String) -> Int {
        let prizeRemainingTime = Helper.stringToDate(remainingTime)
        let prizeRemainingTimeInterval = Int(prizeRemainingTime.timeIntervalSince1970)
        let currentTimeInterval = Int(Date().timeIntervalSince1970)
        return prizeRemainingTimeInterval - currentTimeInterval
    }

一切正常,直到细胞被重复使用,之后倒计时数字不再正确。

这是在UICollectionViewCell中显示倒计时的正确方法,还是有更好的解决方案。

任何人都可以帮我找到解决方法吗?

3 个答案:

答案 0 :(得分:1)

  • 将计时器逻辑移至数据模型。
  • 而不是目标/操作使用Timer
  • 的基于块的API
  • cellForRow中将计时器回调块传递给单元格。
  • 当计时器触发回调块中的代码时,可以更新单元格中的UI。

答案 1 :(得分:1)

根据已接受的答案指南进行编码,希望您喜欢。

MyViewController

protocol MyViewControllerDelegate : class {
    func updateTimer(_ timeString: String)
}

class MyViewController: UIViewController {

    weak var timerDetegate: MyViewControllerDelegate?

    var timer = Timer()
    var time = 0

    fun ViewDidLoad() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
            self.time += 1
            self.timerDetegate?.updateTimer("time \(self.time)")
        })
    }

    ...

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableViewdequeueReusableCell(withIdentifier: "MeCell")
        vc.timerDetegate = cell
        return cell
    }

    ...

}

MyTableViewCell

class MyTableViewCell : UITableViewCell, MyViewControllerDelegate {

    ...

    func updateTimer(_ timeString: String) {
        lblTimeLeft.text = timeString
    }

}

答案 2 :(得分:0)

我实现了这种更简单的方式(不关心性能/延迟)

在..cellForItemAt ..方法中,我调用

cell.localEndTime = yourEndTimeInterval
cell.startTimerProgress()

在集合视图单元格中,我添加了一个启动进度的方法:

    var localEndTime: TimeInterval = 0 //set value from model
    var timer:Timer?
    func timerIsRunning(timer: Timer){
        let diff = localEndTime  - Date().timeIntervalSince1970
        if diff  > 0 {
            self.showProgress()
            return
        }
        self.stopProgress()


    }
    func showProgress(){
        let endDate = Date(timeIntervalSince1970: localEndTime)
        let nowDate = Date()
        let components = Calendar.current.dateComponents(Set([.day, .hour, .minute, .second]), from: nowDate, to: endDate)
        self?.timerLabel?.text = String(format:"%02i:%02i:%02i", components.hour!, components.minute!, components.second!)

    }

    func stopProgress(){
         self?.timerLabel?.text = String(format:"%02i:%02i:%02i", 0, 0, 0)
        self.timer?.invalidate()
        self.timer = nil
    }

    func startTimerProgress() {
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.timerIsRunning(timer:)), userInfo: nil, repeats: true)
        self.timer?.fire()
    }