人類在錶盤上還會設計刻度,雖然這個刻度並不是必要的,不過做出來並不困難,只是畫一條線而已,今天就來實作這邊的程式碼。
struct Tick: Shape {
var tickLength: CGFloat
func path(in rect: CGRect) -> Path {
var p = Path()
p.move(to: CGPoint(x: rect.midX, y: rect.minY))
p.addLine(to: CGPoint(x: rect.midX, y: rect.minY + tickLength))
return p
}
}
struct Tick_Previews: PreviewProvider {
static var previews: some View {
Tick(tickLength: 20)
.stroke(lineWidth: 3)
.previewLayout(.fixed(width: 200, height: 200))
}
}
Tick 是一個 shape,在 init()後,可以用 stroke() 去調整粗細。然後,我們把他畫在 ClockDialView() 裡面。
因為刻度本身會不斷的畫,可以先抽出成一個 some View 的 property。之後再組合進 body 裡面。如果一個 View 裡面的 body 有非常大量的 View,可讀性也會變差的。解決方法是用 @ViewBuilder 的 func 宣告,或是寫一個 property 宣告 some View 後,再組合進 body 裡面。
這邊選擇使用 property,下面的 ticks,就是錶盤上的刻度
struct ClockDialView: View {
var tickLength: CGFloat = 10
var body: some View {
ZStack {
Circle()
.stroke()
.padding(3)
ticks
.padding(3)
HStack {
Spacer()
BackwardsClockNumberView()
Spacer()
}
}
}
var ticks: some View {
![https://ithelp.ithome.com.tw/upload/images/20220909/20140622rPBNfTfIwD.png](https://ithelp.ithome.com.tw/upload/images/20220909/20140622rPBNfTfIwD.png)
ForEach(0..<60) { position in
if position % 5 == 0 {
Tick(tickLength: tickLength)
.stroke(lineWidth: 3)
.rotationEffect(.radians(Double.pi * 2 / 60 * Double(position)))
}
}
}
}
這樣就能在每個數字上,畫出一個刻度,總共 12 個刻度。
如果希望畫出細一點的, 60 個刻度,然後在數字上的刻度比較長,這也很容易做,調整一下 ticks 的程式碼即可。
先寫一個判斷是不是 5 的倍數的 func,只要把 position 傳進去,在確認是 5 的倍數的 position,把 tick length 變長即可,這邊使用的是 1.8 倍長度差。
struct ClockDialView: View {
var tickLength: CGFloat = 5
var body: some View {
ZStack {
Circle()
.stroke()
.padding(3)
ticks
.padding(3)
HStack {
Spacer()
BackwardsClockNumberView()
Spacer()
}
}
}
private func isLongTick(_ position: Int) -> Bool {
return position % 5 == 0
}
var ticks: some View {
ForEach(0..<60) { position in
let longerTick = tickLength * 1.8
Tick(tickLength: isLongTick(position) ? longerTick : tickLength )
.stroke(lineWidth: 3)
.rotationEffect(.radians(Double.pi * 2 / 60 * Double(position)))
}
}
}
結果如下