#はじめに
この記事はDiverse Advent Calendar 2020の18日目の記事です。
業務でいくつかプログレスを作ったので紹介します。
同じようなデザインのプログレスを作る際はぜひご活用ください!
GitHubにこの記事のサンプルを上げてます。
↓実際に動きを見たい方はこちら
https://github.com/Masataka-n/SwiftUIProgress
#Ring
struct RingProgressView: View {
var value: CGFloat
var lineWidth: CGFloat = 6.0
var outerRingColor: Color = Color.black.opacity(0.08)
var innerRingColor: Color = Color.orange
var body: some View {
ZStack {
Circle()
.stroke(lineWidth: self.lineWidth)
.foregroundColor(self.outerRingColor)
Circle()
.trim(from: 0.0, to: CGFloat(min(self.value, 1.0)))
.stroke(
style: StrokeStyle(
lineWidth: self.lineWidth,
lineCap: .square, // プログレスの角を丸くしたい場合は.round
lineJoin: .round
)
)
.foregroundColor(self.innerRingColor)
.rotationEffect(.degrees(-90.0))
}
.padding(.all, self.lineWidth / 2)
}
}
@State var value: CGFloat = 0.0
var body: some View {
RingProgressView(value: value)
.frame(width: 150, height: 150)
.onAppear {
withAnimation(.linear(duration: 5)) {
self.value = 1.0
}
}
}
#Pie
Shapeを継承してPieShapeというものを作っています。
Shapeを自作した場合、アニメーションが適用されないので animatableData
をoverrideする必要があります。
struct PieProgressView: View {
var value: CGFloat
var body: some View {
ZStack {
Circle()
.fill(Color.black.opacity(0.08))
PieShape(progress: value)
.fill(Color.orange)
.rotationEffect(.degrees(-90))
}
}
}
struct PieShape: Shape {
var value: CGFloat
var animatableData: CGFloat {
get { value }
set { value = newValue }
}
func path(in rect: CGRect) -> Path {
Path { path in
let center = CGPoint(x: rect.midX, y: rect.midY)
path.move(to: center)
path.addArc(
center: center,
radius: rect.width / 2,
startAngle: .degrees(0),
endAngle: .degrees(Double(360 * value)),
clockwise: false
)
path.closeSubpath()
}
}
}
@State var value: CGFloat = 0.0
var body: some View {
PieProgressView(value: value)
.frame(width: 150, height: 150)
.onAppear {
withAnimation(.linear(duration: 5)) {
self.value = 1.0
}
}
}
#Square
Rectangleを2つ重ねて上のRectangleのwidthをvalueに応じて変えることで実現してます。
Squareと名付けてますがcornerRadiusを指定して角丸にすることもできます。
struct SquareProgressView: View {
var value: CGFloat
var baseColor: Color = Color.black.opacity(0.08)
var progressColor: Color = Color.orange
var body: some View {
GeometryReader { geometry in
VStack(alignment: .trailing) {
ZStack(alignment: .leading) {
Rectangle()
.fill(self.baseColor)
Rectangle()
.fill(self.progressColor)
.frame(minWidth: 0, idealWidth:self.getProgressBarWidth(geometry: geometry),
maxWidth: self.getProgressBarWidth(geometry: geometry))
}
}
}
}
func getProgressBarWidth(geometry:GeometryProxy) -> CGFloat {
let frame = geometry.frame(in: .global)
return frame.size.width * value
}
}
@State var value: CGFloat = 0.0
var body: some View {
SquareProgressView(value: value)
.frame(height: 20)
//.cornerRadius(10) 角丸も可
.onAppear {
withAnimation(.linear(duration: 5)) {
self.value = 1.0
}
}
}
#さいごに
今回は作成したプログレスを3つ紹介しました。
基本的にコピペで使えると思いますのでぜひご活用ください。