向 UICollectionView 添加多个倒数计时器

Adding Multiple Countdown Timers to UICollectionView

我的目标是在 uicollectionview.

中为每个填充的 uicollectionviewcell 设置唯一的 (hh:mm:ss) 倒计时 timer

下面是我已经能够编译的(缩写的)代码,但我坚持让它以任何身份真正工作......任何指导将不胜感激。

class VC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

var timer = Timer()
var secondsRemaining: Int?

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! ExampleCollectionViewCell    

    let expirationDate = Calendar.current.date(byAdding: .hour, value: 24, to: startDate)
    secondsRemaining = expirationDate?.seconds(from: startDate)

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

    return cell
}

    @objc func countdown() {
    secondsRemaining = secondsRemaining! - 1
    if secondsRemaining == 0 {
        print("CELL TIME HAS EXPIRED!")
        timer.invalidate()
    } else {
        let hours = secondsRemaining! / 3600
        let minutes = (secondsRemaining! % 3600) / 60
        let seconds = (secondsRemaining! % 3600) % 60
        let countdownLabelString = String(format: "%02d:%02d:%02d", hours, minutes, seconds)

        //i need to take this countdownLabelString and set it to the 
        //countdownLabel.text that is an element of each cell. i tried 
        //doing all of this in the cell subclass, but no luck... 
    }
} 
}

集合视图单元格不会不断更新。如果你想让他们更新,你必须告诉他们更新。

如果您希望每个单元格显示不同的剩余时间,您需要一个数据模型来为您显示的每个 indexPath 保存一个单独的 expirationDate。如果您的集合视图是一个简单的一维项目列表,例如 table 视图,那么您可以只使用一维数组。如果您的集合视图显示单元格网格,您可能需要一个二维模型对象数组。

每次将项目添加到数据模型时,都包含一个 expirationDate 值。 (该项目过期时的 Date。)

然后让您的计时器在每次触发时调用集合视图的 reloadData 方法。

在您的 collectionView(collectionView:cellForItemAt:) 方法中,使用 indexPath 确定要显示的数据模型中的项目。查找该 indexPath 的 expirationDate,计算从现在到到期日期的剩余时间,并在单元格中显示该信息。 (使用 Calendar 方法 dateComponents(_:from:to:) 计算从现在到到期日期之间的小时数、分钟数和秒数。)

编辑

不要 每次计时器触发时都减少计数器。使用 dateComponents(_:from:to:)

计算您的到期日期和当前日期之间的差异

编辑#2:

下面是一个示例集合视图控制器,它可以执行您想要的操作:

import UIKit

private let reuseIdentifier = "aCell"

class DatesCollectionVC: UICollectionViewController {

    weak var timer: Timer?
    var dates: [Date] = []
    lazy var componentsFormatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.hour, .minute, .second]
        return formatter
    }()

        
    override func viewDidLoad() {
        
        super.viewDidLoad()

        for _ in 1...100 {
            let interval = Double(arc4random_uniform( 10000)) + 120
            dates.append(Date().addingTimeInterval(interval))
        }

        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            self.collectionView?.reloadData()
        }
    }
    
    // MARK: - UICollectionViewDataSource

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dates.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as? MyCell else {
            return UICollectionViewCell()
        }
        
        let now = Date()
        let expireDate = dates[indexPath.row]
        guard  expireDate > now else {
            cell.intervalLabel.text = "00"
            return cell
        }
        
        let desiredComponents: Set<Calendar.Component> = [.hour, .minute, .second]
        let components = Calendar.current.dateComponents(desiredComponents, from: now, to: expireDate)
        cell.intervalLabel.text = self.componentsFormatter.string(from: components)

        return cell
    }
}

上面的代码如下所示: