使用Swift 3.0建立倒数计时器
在这里,您将看到如何使用Swift 3.0为iOS构建一个简单的计时器。
我假设您对Swift编程语言,Xcode和Storyboard有基本的了解。 如果您需要基础知识方面的帮助或在情节 提要中 设置UI,请访问 www.raywenderlich.com, 以获得一些很棒的初学者教程。
计时器类
我们将使用Apple提供的Timer类。 在文档中定义了一个计时器,如下所示:
“计时器等待直到经过一定的时间间隔,然后触发,将指定的消息发送到目标对象。”
“例如,您可以创建一个 Timer
对象, 该 对象将消息发送到窗口,告诉窗口在一定时间间隔后进行更新。”
创建Timer类的目的是使它易于在特定时间触发动作(例如更新标签或触发方法)。
建立计时器
- 创建一个新的“ Single View Application”,为其命名,并将语言设置为Swift。
- 在情节提要中新建一个视图控制器,或使用预先存在的默认视图控制器。 添加标签。 (此标签将显示开始时间以及以秒,分钟和小时为单位的倒计时。) 添加三个按钮:“开始”,“暂停”和“重置”。 我的初始设置如下:
注意:在标签中设置为占位符文本的内容无关紧要,因为我们将在代码中提供标签文本。 我使它看起来像一个计时器,但它的工作原理与“标签”一词一样好。
但是,您为标签设置的字体将在程序运行时显示。 我选择Courier New,因为它是等距的(所有字母/数字都相同的宽度),并且不会随着数字递减而四处移动。
3.将标签和按钮从情节提要板连接到视图控制器类。
快捷方式:要从Storyboard中的助手编辑器中打开View Controller文件,请按住Option,然后在左侧的Navigation inspector / menu中单击类文件。
我假设您知道如何将标签和按钮连接到适当的类。
4.接下来离开情节提要,转到“视图控制器”类。 在timerLabel出口下,创建以下变量:
var seconds = 60 //此变量将保留秒的起始值。 它可以是大于0的任何数量。
var timer = Timer()
var isTimerRunning = false //这将用于确保一次仅创建一个计时器。
到目前为止,您的代码应如下所示:
您可以擦除didReceiveMemoryWarning()函数,在此演示中我们将不需要它。
5.制作一个包含以下代码的新方法:
func runTimer(){
timer = Timer.scheduledTimer(timeInterval:1,target:self,选择器:(#selector(ViewController.updateTimer)),userInfo:nil,重复:true)
}
此方法调用将初始化计时器。 它指定了timeInterval (一个方法将被调用的频率)和选择器 (该方法将被调用)。
该间隔以秒为单位测量,因此要使其像标准时钟一样工作,我们应将此参数设置为1。
timeInterval:1
选择器参数中的语法有点混乱。 下面的代码应该可以很好地指定在该时间间隔内调用哪个方法。
选择器:(#selector(ViewController.updateTimer))
updateTimer是每秒将被调用的方法的名称。 此方法将更新标签。 我们将在下面的下一步中定义此方法。
userInfo:无,重复:true
现在不用担心userInfo,将其设置为nil。 重复次数应设置为true,因为我们希望计时器再次自动调用自身以保持运行。
6.接下来,在startButtonTapped主体内调用runTimer()方法。
更新计时器方法
7.在其主体中创建以下方法和代码:
func updateTimer(){
seconds-= 1 //这将减少(倒数)秒。
timerLabel.text =“ \(seconds)” //这将更新标签。
}
实际上,计时器中的秒数只是一个每秒更新的UILabel。 没有什么比这更复杂了!
到目前为止,您的代码应如下所示:
注意:我将计时器代码放入了一个辅助方法(称为runTimer)中,该方法在startButtonTapped方法中被调用。 我这样做是因为稍后需要重用此方法。
如果您运行计时器,它应该从60秒开始倒计时。 但是您将无法停止或暂停它。 它将从零开始计数为负数。 因此,让我们继续!
暂停/继续执行
8.要添加“暂停和继续”功能,我们需要将实现添加到pauseButtonTapped方法中。
Swift的Timer类有一个称为invalidate()的方法。 它将停止计时器,但不会重置秒的当前值。 这对于恢复将很有用。
首先添加一个布尔类变量,该变量将跟踪是否应允许暂停按钮恢复。 换句话说,是否已点击暂停。 由于启动应用程序时尚未点击暂停,因此请将其设置为false。
var resumeTapped =否
然后,使用if-else语句在暂停和恢复之间切换。
@IBAction func pauseButtonTapped(_ sender:UIButton){
如果self.resumeTapped ==假{
timer.invalidate()
self.resumeTapped = true
}其他{
runTimer()
self.resumeTapped =否
}
}
第一次点击暂停按钮时,resumeTapped将为false,并且将使用timer.invalidate()停止计时器。
在下一次点击暂停按钮时, runTimer()将再次初始化计时器。 注意:秒数尚未被覆盖,因此应该从中断处开始。
随着点击简历,这将继续交替进行。
重置实施
9.能够将计时器重设为起点也很重要。 在resetButtonTapped方法中,我们将停止计时器并添加功能以将秒数重置为零。
@IBAction func resetButtonTapped(_ sender:UIButton){
timer.invalidate()
seconds = 60 //这里,我们手动输入秒数的重启点,但是将其设置为变量或常量会比较明智。
timerLabel.text =“ \(秒)”
}
10.继续运行计时器!
您的计时器应该运行,暂停/恢复和重置。
但是您会注意到,它看起来不像时钟,并且将秒数远远超过0计数为负数。
在当前设置下,您只能看到以秒为单位的时间,如果您倒计时超过一分钟,则可能会造成混淆。
格式化小时,分钟,秒
11.要格式化标签以显示分钟和小时,我们将需要使用TimeInterval类转换秒。
制作一个名为timeString的新方法。 这将需要一个时间间隔或整数,并返回带有格式化时间的字符串。 现在,标签将使用此字符串更新。
func timeString(time:TimeInterval)->字符串{
让小时= Int(时间)/ 3600
让分钟= Int(时间)/ 60%60
让秒= Int(时间)%60
返回字符串(格式:“%02i:%02i:%02i”,小时,分钟,秒)
}
在updateTimer方法内部
timerLabel.text =“ \(秒)”
与
timerLabel.text = timeString(time:TimeInterval(seconds))
这将通过timeString方法将其发送,在此将首先对其进行格式化,然后将其设置为文本标签。
您的计时器应具有更好的格式,如下所示:
现在您的代码应如下所示:
它似乎运行良好,但是尝试多次点击“开始”按钮,您肯定会发现某些错误。
修复多个计时器/加速错误
12.您可能已经注意到,如果连续多次单击“开始”按钮,时间将开始越来越不规则地计数。
发生这种情况是因为在每次单击按钮时都会创建一个新的Timer对象。 然后,这些新计时器中的每个计时器都会同时控制标签,从而使标签以越来越快的速度变化。
这就是我们开始创建的isTimerRunning变量的作用。 它将跟踪计时器是否正在运行。
var isTimerRunning = false //要确保已在View Controller类中声明了此变量。
接下来,在startButtonTapped主体内,添加围绕创建新计时器的if语句: if isTimerRunning == false {}。
@IBAction func startButtonTapped(_ sender:UIButton){
如果isTimerRunning == false {
runTimer()
}
}
在runTimer()内部,将isTimerRunning设置为true。
在resetButtonTapped内部,我们应该再次将isTimerRunning设置为false,因为我们正在停止并且不想重新启动同一计时器。
@IBAction func resetButtonTapped(_ sender:UIButton){
timer.invalidate()
秒= 0
timerLabel.text = timeString(time:TimeInterval(seconds))
isTimerRunning =假
}
当秒数少于一秒时,停止计时器并发送警报
13.计时器的最重要功能之一是在时间用完时停止计时。
在updateTimer方法内添加if语句,以检查秒数是否小于一。 如果是这样,请使用invalidate()停止计时器,并添加实现以调用警报或执行其他操作以使用户知道计时器已结束。
对于此示例,我将停止计时器。
func updateTimer(){
如果秒<1 {
timer.invalidate()
//发送警报以指示“时间到了!”
}其他{
秒-= 1
timerLabel.text = timeString(time:TimeInterval(seconds))
}
}
现在运行您的计时器,当计时器归零时,它将停止。
这就是您的方法应该如何看待这一点。
整理细节
有一些最后的润色,将使计时器更加人性化。
使用暂停/继续切换标签。
14.首先,“暂停”按钮实际上是双重目的的。 计时器正在运行时为“暂停”,而计时器已暂停则为“恢复”。
按钮的标题应在暂停和恢复之间切换,以反映其当前用途。
要添加此实现,请首先将暂停按钮从情节提要板连接到课程上,为该按钮设置一个插座。 给它起一个类似“ pauseButton”的名称。
接下来,在pauseButtonTapped中 ,一旦点击了暂停按钮,将标题设置为“ Resume”,而再次点击该按钮,则将标题重置为“ Pause” 。
在Swift 3中,用于在按钮上设置标题的语法如下:
self.pauseButton.setTitle(“ Resume”,用于:.normal)
pauseButtonTapped方法应如下所示:
@IBAction func pauseButtonTapped(_ sender:UIButton){
如果self.resumeTapped ==假{
timer.invalidate()
self.resumeTapped = true
self.pauseButton.setTitle(“ Resume”,用于:.normal)
}其他{
runTimer()
self.resumeTapped =否
self.pauseButton.setTitle(“ Pause”,for:.normal)
}
}
启用/禁用开始和暂停按钮
15.使该应用程序更加用户友好并帮助避免错误的其他事情是根据用途启用/禁用暂停和开始按钮。
在启动计时器之前,不应启用“恢复”按钮。
计时器运行后,不应再启用开始按钮。
要在计时器启动后禁用“启动”按钮,请为其建立一个名为startButton的插座。
在startButtonTapped方法中,通过将它添加到if语句中,在第一次点击时禁用开始按钮。 这将确保一旦计时器首次启动后,启动按钮将不再启用。
@IBAction func startButtonTapped(_ sender:UIButton){
如果isTimerRunning == false {
runTimer()
self.startButton.isEnabled =否
}
}
同样,我们不希望在点击开始之前启用“暂停”按钮。 因此,在viewDidLoad中,在应用加载时将其禁用。
覆盖func viewDidLoad(){
super.viewDidLoad()
pauseButton.isEnabled =否
}
计时器启动后,我们需要确保已启用暂停。 在runTimer方法中启用它可以确保如果计时器正在运行,则可以点击pauseButton。
func runTimer(){
timer = Timer.scheduledTimer(timeInterval:1,target:self,选择器:(#selector(ViewController.updateTimer)),userInfo:nil,重复:true)
isTimerRunning = true
pauseButton.isEnabled = true
}
最后,如果轻按了重置按钮,则应禁用暂停,因此请将其添加到resetButtonTapped 。
@IBAction func resetButtonTapped(_ sender:UIButton){
timer.invalidate()
秒= 60
timerLabel.text = timeString(time:TimeInterval(seconds))
isTimerRunning =假
pauseButton.isEnabled =否
}
恭喜,您已成功使用Swift 3构建了一个计时器!
15.现在运行您的计时器!
在Github中完成的项目文件
有关完整的项目源文件,请访问Github 。
进一步的阅读和资料:
https://developer.apple.com/reference/foundation/timer
http://www.ios-blog.co.uk/tutorials/swift/swift-nstimer-tutorial-lets-create-a-counter-application/
https://www.hackingwithswift.com/example-code/system/how-to-make-an-action-repeat-using-timer