译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
用 Timer 倒计时
如果我们结合 Foundation,SwiftUI 和 Combine 框架,可以添加一个定时器到应用中,给用户一点压力。最简单的实现几乎不费力就能做到,但是有一个 bug 需要解决。
首先我们要创建两个新属性:定时器本身,它每秒发射一次,以及一个 timeRemaining 属性,随着定时器的发射每次自减 1,这样就可以告诉用户当前轮次还剩多少时间可用,以便提醒他们加速。
把下面两个新属性添加到 ContentView:
@State private var timeRemaining = 100
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
我们在主线程创建和启动定时器,每条发射,给用户 100 秒来做出回答。
每当定时器发射时,我们需要从 timeRemaining 减 1。当然,我们也可以借助日期的计算来实现倒计时,但这里完全没有必要。
给 ContentView 最外层的 ZStack 添加一个 onReceive() modifier。
.onReceive(timer) { time in
if self.timeRemaining > 0 {
self.timeRemaining -= 1
}
}
提示: 添加一个测试条件确保我们不会跑进负值。
我们的定时器从 100 倒计到 0,但还需要显示这个数字。
Text("Time: \(timeRemaining)")
.font(.largeTitle)
.foregroundColor(.white)
.padding(.horizontal, 20)
.padding(.vertical, 5)
.background(
Capsule()
.fill(Color.black)
.opacity(0.75)
)
如果你放的位置是正确的,现在的布局代码应该是这样的:
ZStack {
Image("background")
.resizable()
.scaledToFill()
.edgesIgnoringSafeArea(.all)
VStack {
Text("Time: \(timeRemaining)")
.font(.largeTitle)
.foregroundColor(.white)
.padding(.horizontal, 20)
.padding(.vertical, 5)
.background(
Capsule()
.fill(Color.black)
.opacity(0.75)
)
ZStack {
再次运行应用 —— 看起来工作正常,对吧?不过这里有一个小问题:
- 查看当前的时间
- 点击 Cmd+H 回到主屏幕
- 等待 10 秒
- 点击应用图标回到应用
- 定时器显示的时间是?
我发现定时器剩余的时间比我们之前离开应用的时候少了 3 秒 —— 也就是说定时器在后台运行了几秒,然后就暂停了 —— 直到应用重新回来。
我们可以做出优化:当应用进入后台或者前台时,相应地暂停或者重启定时器。
首先,添加这个属性来存储应用当前是否激活的状态:
@State private var isActive = true
接下来,我们需要再添加两个 onReceive() modifier,用来维护应用的 isActive。对此,我们可以捕捉 UIApplication.willResignActiveNotification 和 UIApplication.willEnterForegroundNotification 通知,像下面这样:
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
self.isActive = false
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
self.isActive = true
}
最后,修改 onReceive(timer) 函数,当 isActive 时不做倒计时,像这样:
.onReceive(timer) { time in
guard self.isActive else { return }
if self.timeRemaining > 0 {
self.timeRemaining -= 1
}
}
经过这个小修改,倒计时会在应用进入后台时自动暂停 —— 我们不会再神秘地丢失一些秒数。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~