Created
February 29, 2024 19:16
-
-
Save mkaulfers/7973d92aa060a9200b721915a98338dc to your computer and use it in GitHub Desktop.
SwiftUI Asymmetrical Indefinite Progress Indicator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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