Ios 在自定义UIcollectionview单元格中显示计时器';s标签
我已经创建了一个自定义集合视图单元类,它有自己的xib文件。我想显示一个倒计时运行计时器 我有一个可以显示计时器的工作功能:Ios 在自定义UIcollectionview单元格中显示计时器';s标签,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我已经创建了一个自定义集合视图单元类,它有自己的xib文件。我想显示一个倒计时运行计时器 我有一个可以显示计时器的工作功能: class Mainview: UIviewcontroller{ // get the timer value that I want to countdown, e.g 15 mins // then I will pass the the value to the cell class } class TimerCell : UIcollec
class Mainview: UIviewcontroller{
// get the timer value that I want to countdown, e.g 15 mins
// then I will pass the the value to the cell class
}
class TimerCell : UIcollectionviewcell{
func timerRunning() {
timeRemaining = timeRemaining - 1
if (timeRemaining > 0)
{
let minutesLeft = Int(self.timeRemaining) / 60 % 60
let secondsLeft = Int(self.timeRemaining) % 60
self.timerLabel.text = "Refreshes in \(minutesLeft):\(secondsLeft)"
}
func runtime(){
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerRunning), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
}
}
但是因为现在我在cell类中实现了这个函数,所以计时器不会运行。我做错什么了吗?谢谢各位。有几件事:
timeRemaining = timeRemaining - 1
相反,我会保存nextRefreshTime
并计算当前时间和nextRefreshTime
之间经过的时间,以显示剩余时间scheduledTimer
时,这会为您将其添加到运行循环中,因此您不必自己也将其添加到运行循环中
或者,如果要在runloop上使用.commonModes
以允许标签计时器在滚动期间继续,只需使用init
创建计时器,然后将其添加到runloop中
但是使用scheduleTimer
和将它再次添加到运行循环中是没有意义的
datecomponentsformter
很好地显示剩余时间viewDidLoad
中谈到启动计时器。但是,UICollectionViewCell
没有这样的方法(如果您创建一个名称,它将不会使用它)。相反,在cellForItemAt
中调用一些方法来配置单元格- 最初使用
配置单元格;及nextRefreshTime
- 每当
更改时发布一些通知nextRefreshTime
- 将自身添加为该通知的观察者,更新其
李>nextRefreshTime
- 每当收到该通知时,取消任何先前的“标签更新”计时器(如有),并在必要时启动一个新的计时器李>
- 标签更新处理程序应该更新标签
在你称之为的地方,最好贴满code@Sh_Khan我编辑了questionNote
scheduledTimer
已将其添加到当前运行循环中,因此不需要手动将其添加到运行循环中。假设timer
既弱又可选,我建议在使用scheduledTimer
创建和调度计时器之前,先使用timer?.invalidate()
。但这一切都与你的问题无关。你到底从哪里开始计时?也就是说,您在哪里调用运行时
?你真的想在定时计划
中定义运行时
?看起来好像缺少一个大括号。@Rob我在主视图出现时启动计时器。实际上,你可以忽略我的所有代码,我主要想知道在UIcollectionview单元类中显示一个正在运行的倒计时计时器?兄弟,我从API获得了持续时间,比如说15分钟。如何将其应用到您的解决方案中?在我的示例中,在resetTimer
中,添加15*60而不是2*60。bro如果我想在计时器结束后调用API并重新加载collectionview,我可以在哪里调用它?我将刷新数据计时器的计时器处理程序放在哪里,除了重置计时器,你可能会为collection视图重新加载数据。这是一件愚蠢的事情,但如果你不叫我“兄弟”,我将不胜感激。
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
static let resetTimerNotification = Notification.Name("someuniqueidentifier")
// this handles the data refreshes (or whatever), say every two minutes, or whatever
private var nextRefreshTime: Date? {
didSet {
NotificationCenter.default.post(name: ViewController.resetTimerNotification, object: nextRefreshTime)
refreshDataTimer?.invalidate()
if let when = nextRefreshTime {
refreshDataTimer = Timer.scheduledTimer(withTimeInterval: when.timeIntervalSince(Date()), repeats: false) { [weak self] _ in
print("timer fired")
self?.resetTimer() // presumably, defer this until after the data refresh is done
}
}
}
}
private weak var refreshDataTimer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(UINib(nibName: "TimeRemainingCell", bundle: nil), forCellWithReuseIdentifier: "TimeRemaining")
resetTimer()
}
@IBAction func didTapResetButton(_ sender: Any) {
resetTimer()
}
private func resetTimer() {
nextRefreshTime = Date().addingTimeInterval(120) // or however you want to do this
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// lets imagine that cell 0 is the TimeRemainingCell
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TimeRemaining", for: indexPath) as! TimeRemainingCell
cell.configure(for: nextRefreshTime)
return cell
}
... configure other types of cells
}
}
class TimeRemainingCell: UICollectionViewCell {
// MARK: - Properties
@IBOutlet weak var timeRemainingLabel: UILabel!
private var nextRefreshTime: Date? {
didSet {
labelUpdateTimer?.invalidate()
if nextRefreshTime != nil {
let timer = Timer(fire: nextRefreshTime!, interval: 0, repeats: false) { [weak self] timer in
// note, if cell is deallocated for any reason, let's stop the timer
guard let strongSelf = self else {
timer.invalidate()
return
}
strongSelf.updateLabel()
}
RunLoop.current.add(timer, forMode: .commonModes)
labelUpdateTimer = timer
}
}
}
private weak var labelUpdateTimer: Timer?
/// Formatter for time remaining
///
/// Note, this gets us out of manually calculating minutes and seconds remaining
private static let formatter: DateComponentsFormatter = {
let _formatter = DateComponentsFormatter()
_formatter.unitsStyle = .positional
_formatter.allowedUnits = [.minute, .second]
_formatter.zeroFormattingBehavior = .pad
return _formatter
}()
// MARK: - init/deinit methods
override init(frame: CGRect) {
super.init(frame: frame)
addNotificationObserver()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addNotificationObserver()
}
deinit {
labelUpdateTimer?.invalidate()
}
// MARK: - Configuration methods
/// Add notification observer
private func addNotificationObserver() {
NotificationCenter.default.addObserver(forName: ViewController.resetTimerNotification, object: nil, queue: .main) { [weak self] notification in
self?.nextRefreshTime = notification.object as? Date
self?.updateLabel()
}
}
/// Configure the cell for your model object.
///
/// Called by collectionView(_:cellForItemAt:).
///
/// Also starts the refresh timer.
///
/// - Parameter object: Your model object
func configure(for nextRefreshTime: Date?) {
self.nextRefreshTime = nextRefreshTime
}
// MARK: - Label updating
private func updateLabel() {
let now = Date()
if let when = nextRefreshTime {
timeRemainingLabel.text = TimeRemainingCell.formatter.string(from: now, to: when)
} else {
timeRemainingLabel.text = "No time remaining"
}
}
}