【问题标题】:Having collectionViewCell.label.text Change Every Second with Timer使用计时器让 collectionViewCell.label.text 每秒更改一次
【发布时间】:2020-08-13 23:49:37
【问题描述】:

我目前正在学习编写 swift 应用程序,并正在尝试自己做一些项目。我目前的个人挑战是做一个倒数计时器应用程序。这个概念很简单:用户从 UIDatePicker 输入一个日期,然后应用程序显示距离他的各种事件列表的剩余时间(使用用户默认值将事件保存在内存中)。所有上述事件都显示在集合视图中(请参阅下面的屏幕截图)。

我遇到了一些对我的实际技能来说太复杂的问题,我想你们可能会有答案,或者至少有一些建议!这是我的问题:我希望今天和事件之间的剩余时间每秒减少,并通过 collectionViewCell 内的标签显示。我找到了一种非常简单的方法来做到这一点,有一个计时器,但是用 collectionViewCell 实现上述解决方案让我很头疼。

以下是我想分享的代码摘录,希望够用了:

@objc func UpdateTimeLabel(index: Int) -> String {
    
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
    dateFormatter.timeZone = userCalendar.timeZone
    
    let date = dateFormatter.date(from: UserDefaults.standard.array(forKey: "dates")![index] as! String)!
    
    let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, .second], from: currentDate, to: date)

    return "\(timeLeft.day!) days \(timeLeft.hour!) hours \(timeLeft.minute!) minutes \(timeLeft.second!) seconds"
    
}

这是我希望每秒触发的函数。它目前的制作方式是,它的属性(称为 index)是 collectionViewCell 的 indexPath.row。它引用存储为 UserDefaults 的事件日期数组。 collectionView 中的单元格数与数组中的事件数一样多。

请看下面我在 collectionView forItemAt 函数中实现它的方式:

   func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
            
        // Configure the state of the cell based on the propertires of the card if reprensents
        let cardCell = cell as? EventCollectionViewCell
        
        // UI Configuration
        cardCell?.eventTitleLabel.text = ((UserDefaults.standard.array(forKey: "events")![indexPath.row]) as! String)
        
        cardCell?.eventDateLabel.text = ("Event on: " + "\((UserDefaults.standard.array(forKey: "dates")![indexPath.row]) as! String)")

        cardCell?.countdownLabel.text = UpdateTimeLabel(index: indexPath.row)
    
        cardCell?.eventView.layer.cornerRadius = 10
          
    }

实际结果是每个单元格都显示了今天和事件之间的剩余时间。这已经比我想象的我一个人能做的还要多!!!

Results of actual code

我认为你们中的一个可能介入的地方是帮助我回答这个问题:应该在哪里放置一个类似于下面代码的计时器,以便 cardCell.countdownLabel.text 成为每秒更新一次?

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

我尝试了所有我能想到的方法,但现在遇到了障碍。我的项目中还有很多事情要解决,所以我还没有完全停止。如果您需要更多代码行和/或精度,请告诉我,我会为您提供您认为有帮助的任何内容。

非常感谢您抽出宝贵时间查看我的问题,

路易·G

【问题讨论】:

    标签: swift timer uicollectionview label uicollectionviewcell


    【解决方案1】:

    将此方法UpdateTimeLabel方法添加到EventCollectionViewCell中并像这样修改方法

    @objc func UpdateTimeLabel() {
        let userCalendar = Calendar(identifier: .indian)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
        dateFormatter.timeZone = userCalendar.timeZone
        
        let date = dateFormatter.date(from: UserDefaults.standard.array(forKey: "dates")![index] as! String)!
        
        let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, .second], from: Date(), to: date)
    
        countdownLabel.text = "\(timeLeft.day!) days \(timeLeft.hour!) hours \(timeLeft.minute!) minutes \(timeLeft.second!) seconds"
        
    }
    

    完成此操作后,在EventCollectionViewCell 中添加属性indexEventCollectionViewCell 中的索引触发计时器的didSet 例如:

    var index: Int {
        didSet {
            let timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(UpdateTimeLabel), userInfo: nil, repeats: true)
            timer.fire()
        }
    }
    

    替换

    cardCell?.countdownLabel.text = UpdateTimeLabel(index: indexPath.row)
    

    cardCell?.index = indexPath.row
    

    【讨论】:

    • 感谢@satyen 的快速回答!可悲的是,我最终得到与以前相同的结果:显示倒计时,但不是每秒更新一次。我按照您的建议实现了该功能。如果您需要更多代码摘录,请告诉我!
    • 能否请您核对并确认您添加了timer.fire()
    • 能否请您核对并确认您添加了timer.fire()
    • 我确认我完全按照你的建议做了; timer.fire() 和一切!
    • @SatyenChauhan 极好的解决方案!最简单的一种。你能帮我使计时器失效吗?我试过了,但计时器没有停止。谢谢
    【解决方案2】:

    我找到了为什么@Satyen 建议的解决方案不起作用!好的,我知道,距离他上次回答已经过去了将近一个月,但我不得不说,当我看到它没有修复我的应用程序并决定从事其他项目时,我感到非常沮丧,希望其他人能加入并提供另一个同时解决。无论如何,我今天早上决定通过几次会议来找到问题,我很自豪地报告我做到了!

    好的,这就是问题所在: 我使用了一个名为“当前日期”的变量作为今天的日期。这个变量是在 UpdateTimeLabel 函数之外声明的,并在浴缸右侧的 dateComponents 中进行了转换。结果:当前日期并非每秒刷新一次,因此每次将事件日期与 currentDate 进行比较时,结果都保持不变。

    这是工作代码:

    @objc func UpdateTimeLabel() {
    
        let userCalendar = Calendar.current
        let todayDate = Date()
        let components = userCalendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: todayDate)
        let currentDate = userCalendar.date(from: components)!
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
        dateFormatter.timeZone = userCalendar.timeZone
    
        let date = dateFormatter.date(from: UserDefaults.standard.array(forKey: "dates")![index] as! String)!
    
        let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, .second], from: currentDate, to: date)
    
        countdownLabel.text = "\(timeLeft.day!) days \(timeLeft.hour!) hours \(timeLeft.minute!) minutes \(timeLeft.second!) seconds"
    
        if currentDate >= date {
    
            countdownLabel.text = "Cheers! This event has occured already."
            print("An event expired.")
    
        }
    
    }
    

    由这个 var 索引触发,正如 @Satyen 所建议的:

    var index: Int = 0 {
        didSet {
            
            timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(UpdateTimeLabel), userInfo: nil, repeats: true)
            timer.fire()
            print("timer fired")
            
        }
    }
    

    现在一切都按预期工作!我仍然进行了一些效率调整以使我的代码更简单,但总体而言,它现在显示剩余时间并每秒减少!好激动!!

    再次感谢@Satyen 的宝贵意见!

    【讨论】:

    • 你知道如何让定时器失效了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2021-01-13
    相关资源
    最近更新 更多