Playback speed
×
Share post
Share post at current time
0:00
/
0:00

💡 SwiftUI FYI #5 - Circular Progress View

Simple, yet elegant progress view

Easily build a custom circular progress view by utilizing a few SwiftUI view modifiers. In particular taking advantage of the .trim, .stroke, and .rotationEffect modifiers. Of course animating the progress updates using .animate.

🚨 You can find all code examples on Github now. Would appreciate a Star ⭐️ on the repo :)

🤝 Find more about me on saidmarouf.com. I’m also on XThreads, and LinkedIn

Thanks for reading Your Weekly SwiftUI FYI 💡! Subscribe for free to receive new posts and support my work.


import SwiftUI

struct ContentView: View {
    
    @State var completed: Double = 0.0
    
    private var progress: Double {
        return completed / 1.0
    }
    
    var body: some View {
        VStack {
            
            CircleProgressView(progress: progress, lineWidth: 16)
                .frame(width: 200)
                .padding()
            
            CircleProgressView(progress: progress, lineWidth: 12)
                .frame(width: 100)
                .padding()
            
            CircleProgressView(progress: progress, lineWidth: 8)
                .frame(width: 40)
                .padding()
            
            CircleProgressView(progress: progress, lineWidth: 3)
                .frame(width: 40)
                .padding()
            
            Spacer()
            
            Button {
                completed += 0.1
            } label: {
                Text("Update Progress")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding(.vertical, 40)
    }
}

struct CircleProgressView: View {
    
    var progress: Double
    var lineWidth: CGFloat
    
    var body: some View {
        
        ZStack {
            Circle().stroke(
                .secondary.opacity(0.4),
                lineWidth: lineWidth
            )

            Circle()
                .trim(from: 0, to: min(progress, 1.0))
                .stroke(
                    .green.gradient,
                    style: StrokeStyle(
                        lineWidth: lineWidth,
                        lineCap: .round
                    )
                )
            .rotationEffect(.degrees(-90))
            .animation(.easeOut(duration: 0.25), value: progress)
        }
    }
}

#Preview {
    ContentView()
}