LeetCode 刷題時總是要計算一下自己到底解題解了多久, LeetCode 右上角剛好有一個很佛心的計時器可以幫助我們解決這個問題,而本篇要把這個功能利用 SwiftUI 做進去 App 裏面。
為了更完美計算出 LeetCode 寫題的時間,所以需要製作一個計時器計算我們每一題到底花了多少時間,這個計時器不只是定時計算時間,而且每秒需要更新到畫面上。
如圖我們需要一開始顯示時鐘 Icon,點擊後開始從一秒往上疊加自動計時,再點一次計時文字,則會隱藏,再次顯示時鐘 Icon,而時鐘 Icon 會隨著上次有時間顯示成藍色,但是點擊計時文字右邊的 Icon 會重置秒數,導致時鐘 Icon 也會因為重置 0 而顏色變成灰色。
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
首先我們製造一個 timer 它會自動計數。
// 記錄計時秒數狀態,隨時更新 UI
@State var currentTime = 0
Text("\(currentTime)")
.font(.system(size: 18))
.padding(8)
.foregroundStyle(.black)
.onReceive(timer) { input in
currentTime += 1
}
顯示計時文字設定如上,這裡比較特別的是用了 .onReceive(timer) 去監聽 timer 更新後會有通知,而接收了通知後 currentTime 就加一。
但是我們要顯示的格式是 HH:MM:SS
這種小時+分鐘+秒數的格式,所以有個轉換格式的方法。
func formattedTime(_ seconds: Int) -> String {
let hours = seconds / 3600
let minutes = (seconds % 3600) / 60
let seconds = seconds % 60
return String(format: "%02d : %02d : %02d", hours, minutes, seconds)
}
計時文字右邊有個重置 Icon 這裡的設計如下,因為點擊後會把狀態清除,所以利用了 .onTapGesture 製作點擊監聽事件。(因為懶得再外層加上 Button)
Image(systemName: "clock")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.foregroundColor(.black)
.onTapGesture {
// 重置狀態參數
isShowTimer = false
currentTime = 0
}
另外可以留意到 systemName: "clock"
這個設定是直接取用 iOS 內建的 Icon 圖,我們就不必另外塞圖到資源檔案。
詳細可以到 Apple 官網查看有哪些 Icon 哦!它叫做『SF Symbols』。
完整程式碼如下,如果想 run 看看可以複製回去使用。
struct ContentView: View {
@State var currentTime = 0
@State var isShowTimer = false
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Button(action: {
isShowTimer.toggle()
}) {
if(isShowTimer){
let time = formattedTime(currentDate)
HStack{
Text("\(time)")
.font(.system(size: 18))
.padding(8)
.foregroundStyle(.black)
.onReceive(timer) { input in
currentTime += 1
}
Image(systemName: "clock")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
.foregroundColor(.black)
.onTapGesture {
isShowTimer = false
currentTime = 0
}
}.padding(8)
.background(
Color("ColorGray")
.clipShape(RoundedRectangle(cornerRadius:10))
)
}else{
Image(systemName: "stopwatch")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.foregroundColor((currentTime != 0) ? .blue : .gray)
}
}
}
func formattedTime(_ seconds: Int) -> String {
let hours = seconds / 3600
let minutes = (seconds % 3600) / 60
let seconds = seconds % 60
return String(format: "%02d : %02d : %02d", hours, minutes, seconds)
}
}
完整畫面如圖,一個完美的計時器就完成了,LeetCode 刷題紀錄時間就靠它。
本篇其實意外的覺得 Timer 與 SwiftUI 的互動特別簡單,以往來說寫法都會特別複雜,但是這次學起來發現居然寫個幾行就結束,覺得不可思議,希望大家喜歡這篇教學。