Skip to main content

Circular Progress Bar

Beschreibung

Die CircularProgressBar ist eine wiederverwendbare SwiftUI-Komponente, mit der du einen animierten, kreisförmigen Fortschrittsbalken inklusive Prozentanzeige erstellen kannst.
Sie eignet sich für Lade-, Download- oder Status-Visualisierungen in iOS-, iPadOS- und macOS-Apps.

🔍 Zweck

  • Visuelle Darstellung von Fortschrittswerten (0 – 100 %) als Kreisdiagramm
  • Anpassbar über lineWidth, Farb-Gradienten und Bindings
  • Enthält eine Demo-View mit Slider und Zufalls-Button, um das Verhalten direkt auszuprobieren

📄 Codebeispiel

import SwiftUI

struct CircularProgressBar: View {
    /// The progress value (between 0.0 and 1.0)
    @Binding var progress: Double

    var lineWidth: CGFloat = 20
    var gradientColors: [Color] = [Color.blue, Color.green]

    var body: some View {
        ZStack {
            // Background circle
            Circle()
                .stroke(
                    Color.gray.opacity(0.2),
                    style: StrokeStyle(lineWidth: lineWidth)
                )
                .shadow(color: Color.black.opacity(0.05), radius: 5, x: 0, y: 2)

            // Foreground circle with gradient
            Circle()
                .trim(from: 0.0, to: min(progress, 1.0))
                .stroke(
                    AngularGradient(
                        gradient: Gradient(colors: gradientColors),
                        center: .center
                    ),
                    style: StrokeStyle(lineWidth: lineWidth, lineCap: .round)
                )
                .rotationEffect(.degrees(-90))
                .shadow(color: gradientColors.last!.opacity(0.3), radius: 10, x: 0, y: 5)
                .animation(.easeOut(duration: 0.8), value: progress)

            // Percentage label
            Text("\(Int(progress * 100))%")
                .font(.system(size: 40, weight: .bold, design: .rounded))
                .foregroundStyle(
                    .linearGradient(
                        colors: gradientColors,
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                )
                .shadow(color: Color.black.opacity(0.15), radius: 2, x: 1, y: 2)
        }
        .frame(width: 180, height: 180)
    }
}

// Interactive demo
struct CircularProgressBarDemo: View {
    @State private var progress: Double = 0.5

    var body: some View {
        VStack(spacing: 32) {
            CircularProgressBar(progress: $progress)
            Slider(value: $progress, in: 0...1)
                .padding(.horizontal, 40)

            Button("Random Progress") {
                withAnimation {
                    progress = Double.random(in: 0...1)
                }
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

#Preview {
    CircularProgressBarDemo()
}