swift - 如何在 swift 中为实时倒数计时器添加时间
问题描述
我对 swift 相当陌生,并且正在尝试拥有一个实时倒数计时器,您可以通过按下按钮来增加时间。我在另一个 StackOverflow 帖子中找到了计时器的原始代码:
@objc func UpdateTime() {
let userCalendar = Calendar.current
// Set Current Date
let date = Date()
let components = userCalendar.dateComponents([.hour, .minute, .month, .year, .day, .second], from: date)
let currentDate = userCalendar.date(from: components)!
// Set Event Date
var eventDateComponents = DateComponents()
eventDateComponents.year = 2020
eventDateComponents.month = 09
eventDateComponents.day = 20
eventDateComponents.hour = 00
eventDateComponents.minute = 00
eventDateComponents.second = 00
eventDateComponents.timeZone = TimeZone(abbreviation: "GMT")
// Convert eventDateComponents to the user's calendar
let eventDate = userCalendar.date(from: eventDateComponents)!
// Change the seconds to days, hours, minutes and seconds
let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, .second], from: currentDate, to: eventDate)
// Display Countdown
daysCount.text = "\(timeLeft.day!)d \(timeLeft.hour!)h \(timeLeft.minute!)m \(timeLeft.second!)s"
// Show diffrent text when the event has passed
endEvent(currentdate: currentDate, eventdate: eventDate)
}
func endEvent(currentdate: Date, eventdate: Date) {
if currentdate >= eventdate {
daysCount.text = "0d 0h 0m 0s"
// Stop Timer
timer.invalidate()
}
}
我有一个按钮的 IBAction,理想情况下你会按下它,它会为计时器增加 30 天。我试图做我在另一篇文章中发现的类似的事情,但无法让它工作。
let date = startDate.addingTimeInterval(5 * 60)
我真的很感激这里的任何指导。谢谢。
解决方案
您需要的第一件事是某种“目标值”,您可以轻松更新它,但您的持续时间和格式代码也可以参考
var targetDate: Date = Date()
因为我想更新这个值,所以我给了它一个初始/默认值。您将需要将其更新为更有用的东西,也许viewDidLoad
您可以执行类似...
let calendar = Calendar.current
targetDate = calendar.date(byAdding: .day, value: 7, to: Date())!
理想情况下,这将是一些自包含模型的一部分,但只是步骤。
接下来,我们需要一些方法来更新 UI
var timer: Timer?
//...
let timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(timerTicked(_:)), userInfo: nil, repeats: true)
self.timer = timer
好的,所以,这设置了一个每半秒计时一次的计时器,它允许我们更新 UI。
为此,我实际上使用了两个函数,原因是我可以根据需要独立于计时器格式化标签
@objc func timerTicked(_ timer: Timer) {
formatDuration(from: Date(), to: targetDate)
}
func formatDuration(from: Date, to: Date) {
let text = durationFormatter.string(from: to.timeIntervalSince(from))
label.text = text
}
现在,我使用 aDurationFormatter
来格式化输出,因为它提供了许多额外的灵活性、选项以及最重要的本地化。
lazy var durationFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute, .second]
formatter.unitsStyle = .brief
return formatter
}()
好的,所以,这为我们提供了倒数计时器视图控制器的基本概念(我们可以轻松修改,以便目标日期实际上来自某种可插入模型,以便我们可以重用视图,但我会留下那个给你)。
现在,最后一部分,如何“获得更多时间”。答案是,你实际上已经看到了,就在顶部,我初始化targetDate
.
日期/时间操作并不总是像“只需添加几秒钟”那么简单,涉及很多规则(一团糟)。
因此,在这种情况下,我们使用 a Calendar
,除了为我们处理所有“肮脏”的工作之外,它也更容易阅读和理解。
@IBAction func needMoreTime(_ sender: Any) {
// A list of date components we're willing to change
let components: [Calendar.Component] = [.day, .hour, .minute]
// A random amount of time to be added to a random date component
let randomValue = Int.random(in: 1...10)
// The component we're going to modify
let component = components.randomElement() ?? .minute
// Grab a calendar instance
let calendar = Calendar.current
// Update the target date
targetDate = calendar.date(byAdding: component, value: randomValue, to: targetDate)!
}
本质上,此方法将随机时间量添加到日期的随机部分,但您可以轻松修改它以执行您想要的任何操作。
完整的例子...
而且,因为随机的、断章取义的代码并不总是能理解,这是我为测试我的理论而编写的基本示例......
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
var targetDate: Date = Date()
var timer: Timer?
lazy var durationFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute, .second]
formatter.unitsStyle = .brief
return formatter
}()
override func viewDidLoad() {
super.viewDidLoad()
let calendar = Calendar.current
targetDate = calendar.date(byAdding: .day, value: 7, to: Date())!
formatDuration(from: Date(), to: targetDate)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
formatDuration(from: Date(), to: targetDate)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Personal preference
let timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(timerTicked(_:)), userInfo: nil, repeats: true)
self.timer = timer
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
timer?.invalidate()
timer = nil
}
@objc func timerTicked(_ timer: Timer) {
formatDuration(from: Date(), to: targetDate)
}
func formatDuration(from: Date, to: Date) {
let text = durationFormatter.string(from: to.timeIntervalSince(from))
label.text = text
}
@IBAction func needMoreTime(_ sender: Any) {
// A list of date components we're willing to change
let components: [Calendar.Component] = [.day, .hour, .minute]
// A random amount of time to be added to a random date component
let randomValue = Int.random(in: 1...10)
// The component we're going to modify
let component = components.randomElement() ?? .minute
// Grab a calendar instance
let calendar = Calendar.current
// Update the target date
targetDate = calendar.date(byAdding: component, value: randomValue, to: targetDate)!
}
}
推荐阅读
- mysql - 当 count = 0 时,SQL 查询不返回值/新行;我希望它返回 0
- msbuild - MSBuild:如何找出特定文件添加到 _CopyFilesMarkedCopyLocal 的位置?
- stripe-payments - 条纹连接的帐户 webhook 因未使用我的帐户创建的错误事件而被解雇
- django - 带有 Django Rest Auth 的自定义注册表单 - 错误:save() 采用 1 个位置参数,但给出了 2 个
- firebase - Firebase 提供了哪些解决方案来降低实时数据库的成本?
- if-statement - Power BI 中具有多个条件的 DISCOUNT
- .net-core - 使用外部系统的域服务
- xml - XSL 选择变量标签
- azure-pipelines - 有条件地将 --dry-run 添加到 Azure Pipelines 中的发布步骤
- ios - 努力使集合视图高度适合内容