環境
- macOS Monteley(12.4)
- Xcode(13.4.1)
- Swift(5.6.1)
実装
執筆時点で標準では用意されていないようなので、Circleを利用して実装してみました。
あまり一般的ではないと思いますが、逆回転にも対応している実装になります。
CirclarProgress.swift
struct CirclarProgress: View {
let progress: Int
let color: Color
let isInserve: Bool
let strokeWidth: CGFloat
var lineCap: CGLineCap = .butt
var angle: Double = -90
private var from: Double {
if isInserve {
return 1 - Double(progress) / 100
} else {
return 0.0
}
}
private var to: Double {
if isInserve {
return 1
} else {
return Double(progress) / 100
}
}
private var offset: CGFloat {
strokeWidth / 2
}
var body: some View {
Circle()
.trim(from: from, to: to)
.stroke(color, style: StrokeStyle(lineWidth: CGFloat(strokeWidth), lineCap: lineCap))
.rotationEffect(Angle(degrees: angle))
.padding(offset)
.aspectRatio(1, contentMode: .fit)
.animation(.easeOut, value: progress)
}
}
動作イメージ
備考
- strokeの描画はCircleの縁から内と外に向かって広がるため、Circleに設定したsizeで表示を収めたい場合は、strokeで設定した幅の半分のpaddingが必要になります。
- strokeの描画が3時の方向から始まるため、90度傾けることで0時の方向から始まるようにしています。(ソースではカスタマイズ可能にしています。)
- バーの背景は単純に透過カラーであったり、ゲージを入れたいこともあると思うので、あえて含めていないです。
- colorの部分にGradientを渡すことでグラデーションをつけることも可能です。
- アニメーションはお好みで
参考
Circle: https://developer.apple.com/documentation/swiftui/circle
stroke: https://developer.apple.com/documentation/swiftui/shape/stroke(_:style:)