在 UICollectionViewCell 中添加带计时器的倒计时标签的最佳方法,即使在单元格被重用后也能正常工作
The best way of adding countdown label with timer in UICollectionViewCell which works fine even after cell is being reused
我有一个在 UICollectionView
中呈现给用户的项目列表。这些项目有一个倒计时标签,以显示该项目可用的剩余时间。
我在 UICollectionViewCell
中使用 Timer
来显示剩余时间,例如:
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 中显示倒计时的正确方法还是有更好的解决方案。
谁能帮我找到解决办法?
我实现了这种更简单的方法(不关心 performance/latency)
在 ..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()
}
- 将计时器逻辑移至数据模型。
- 而不是 target/action 使用
Timer
的基于块的 API。
- 在
cellForRow
中将计时器回调块传递给单元格。
- 当计时器触发时,回调块中的代码可以更新单元格中的 UI。
根据已接受的答案指南进行编码,希望您喜欢。
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
}
}
我有一个在 UICollectionView
中呈现给用户的项目列表。这些项目有一个倒计时标签,以显示该项目可用的剩余时间。
我在 UICollectionViewCell
中使用 Timer
来显示剩余时间,例如:
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 中显示倒计时的正确方法还是有更好的解决方案。
谁能帮我找到解决办法?
我实现了这种更简单的方法(不关心 performance/latency)
在 ..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()
}
- 将计时器逻辑移至数据模型。
- 而不是 target/action 使用
Timer
的基于块的 API。 - 在
cellForRow
中将计时器回调块传递给单元格。 - 当计时器触发时,回调块中的代码可以更新单元格中的 UI。
根据已接受的答案指南进行编码,希望您喜欢。
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
}
}