我想实现一个基于当前时间和结束时间的倒计时器。
例如:
当前时间:20:30:30
结束时间始终是:23:59:59
-> 我将实现一个倒计时器:03:29:29
我下面的代码就是这样做的,但我觉得它不是很漂亮。我希望我的结束时间是动态的,而不是硬性规定的数字:23、59、59。
以下是我的全部代码
struct TimerView: View {
@State var timeRemaining = Calendar(identifier: .gregorian).dateComponents(in: .current, from: Date())
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
HStack(spacing: 12) {
timerStringView(timer: hourString(date: timeRemaining))
timerStringView(timer: minuteString(date: timeRemaining) )
timerStringView(timer: secondString(date: timeRemaining))
}
.frame(width: 300, height: 34)
.background(Color.gray)
.onReceive(timer) { _ in
timeRemaining = Calendar(identifier: .gregorian).dateComponents(in: .current, from: Date())
}
}
func timerStringView(timer: String) -> some View {
Text(timer)
.font(.system(size: 18, weight: .bold))
.foregroundColor(.black)
.background(Color.white)
.cornerRadius(6)
}
func hourString(date: DateComponents) -> String {
return String(format: "%02i", 23 - (date.hour ?? 00))
}
func minuteString(date: DateComponents) -> String {
return String(format: "%02i", 59 - (date.minute ?? 00))
}
func secondString(date: DateComponents) -> String {
return String(format: "%02i", 59 - (date.second ?? 00))
}
}
更好的方法是使用
DateComponents
进行日期数学计算,有一个 API dateComponents(_:from:to:)
,其中 from
和 to
也可以是 DateComponents
struct TimerView: View {
@State private var differenceComponents = DateComponents()
private var endDateComponents = DateComponents(hour:23, minute: 59, second: 59)
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
private let calendar = Calendar(identifier: .gregorian)
var body: some View {
HStack(spacing: 12) {
timerStringView(value: differenceComponents.hour ?? 0)
timerStringView(value: differenceComponents.minute ?? 0 )
timerStringView(value: differenceComponents.second ?? 0)
}
.frame(width: 300, height: 34)
.background(Color.gray)
.onReceive(timer) { _ in
let nowComponents = calendar.dateComponents([.hour, .minute, .second], from: .now)
differenceComponents = calendar.dateComponents([.hour, .minute, .second], from: nowComponents, to: endDateComponents)
}
}
func timerStringView(value: Int) -> some View {
Text(String(format: "%02d", value))
.font(.system(size: 18, weight: .bold))
.foregroundColor(.black)
.background(Color.white)
.cornerRadius(6)
}
}