Skip to content

Instantly share code, notes, and snippets.

@mkaulfers
Created February 29, 2024 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkaulfers/7973d92aa060a9200b721915a98338dc to your computer and use it in GitHub Desktop.
Save mkaulfers/7973d92aa060a9200b721915a98338dc to your computer and use it in GitHub Desktop.
SwiftUI Asymmetrical Indefinite Progress Indicator
//
// IndefiniteProgressIndicator.swift
//
// Created by Matthew Kaulfers on 2/29/24.
//
import SwiftUI
struct IndefiniteProgressIndicator: View {
@State private var rotate1 = false
@State private var animate1 = false
@State private var trimStart1 = 0.75
@State private var trimEnd1 = 0.76
@State var animationDuration1 = 1.5
@State private var rotate2 = false
@State private var animate2 = false
@State private var trimStart2 = 0.13
@State private var trimEnd2 = 0.14
@State var animationDuration2 = 2.0
@State private var rotate3 = false
@State private var animate3 = false
@State private var trimStart3 = 0.33
@State private var trimEnd3 = 0.37
@State var animationDuration3 = 2.5
var body: some View {
ZStack {
ProgressSegment(rotate: $rotate1,
trimStart: $trimStart1,
trimEnd: $trimEnd1,
animationDuration: $animationDuration1)
ProgressSegment(rotate: $rotate2,
trimStart: $trimStart2,
trimEnd: $trimEnd2,
animationDuration: $animationDuration2)
ProgressSegment(rotate: $rotate3,
trimStart: $trimStart3,
trimEnd: $trimEnd3,
animationDuration: $animationDuration3)
}
}
}
struct ProgressSegment: View {
@Binding private var rotate: Bool
@Binding private var trimStart: Double
@Binding private var trimEnd: Double
@Binding var animationDuration: Double
var body: some View {
Circle()
.trim(from: trimStart, to: trimEnd)
.stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round, lineJoin: .round))
.foregroundColor(.white)
.rotationEffect(.degrees(rotate ? -360 : 0))
.onAppear {
withAnimation(Animation.linear(duration: animationDuration).repeatForever(autoreverses: false)) {
rotate = true
}
Timer.scheduledTimer(withTimeInterval: animationDuration, repeats: true) {_ in
withAnimation(.easeInOut(duration: 0.5)) {
trimEnd = Double.random(in: (trimStart)...(trimStart + 0.2))
}
}
}
}
init(rotate: Binding<Bool>,
trimStart: Binding<Double>,
trimEnd: Binding<Double>,
animationDuration: Binding<Double>) {
self._rotate = rotate
self._trimStart = trimStart
self._trimEnd = trimEnd
self._animationDuration = animationDuration
}
}
#Preview {
IndefiniteProgressIndicator()
.padding()
.background(Color.black)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment