This article is the 18th day article of Diverse Advent Calendar 2020. I made some progresses in my work, so I will introduce them. Please use it when you make a progress with a similar design!
I have a sample of this article on GitHub. ↓ Click here if you want to see the actual movement 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, //If you want to round the corners of the progress.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
I inherited Shape and made something called Pie Shape.
If you create your own Shape, you will need to override animatableData
as the animation will not be applied.
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
It is realized by stacking two Rectangles and changing the width of the above Rectangle according to the value. We call it Square, but you can also specify cornerRadius to round the corners.
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(Color.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)Rounded corners are also possible
.onAppear {
withAnimation(.linear(duration: 5)) {
self.value = 1.0
}
}
}
This time, I introduced three progresses I created. I think that you can basically use it with copy and paste, so please use it.
Recommended Posts