Created
January 21, 2024 04:49
-
-
Save mazefest/d29438e2d50c5d8269a7a8b84aa3459c to your computer and use it in GitHub Desktop.
Activity Rings
This file contains hidden or 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
struct ActivityRingView: View { | |
@Binding var progress: CGFloat | |
var mainColor: Color = .red | |
var lineWidth: CGFloat = 20 | |
var endColor: Color { | |
mainColor.darker(by: 15.0) | |
} | |
var startColor: Color { | |
mainColor.lighter(by: 15.0) | |
} | |
var backgroundColor: Color { | |
return mainColor.opacity(0.15) | |
} | |
var body: some View { | |
GeometryReader { geo in | |
ZStack { | |
Circle() | |
.stroke(backgroundColor, lineWidth: lineWidth) | |
Circle() | |
.trim(from: 0, to: progress) | |
.stroke( | |
AngularGradient( | |
gradient: Gradient(colors: [startColor, endColor]), | |
center: .center, | |
startAngle: .degrees(0), | |
endAngle: .degrees(360) | |
), | |
style: StrokeStyle(lineWidth: lineWidth, lineCap: .round) | |
) | |
.rotationEffect(.degrees(-90)) | |
Circle() | |
.frame(width: lineWidth, height: lineWidth) | |
.foregroundColor(startColor) | |
.offset(y: -1 * (geo.size.height / 2)) | |
} | |
.rotationEffect(overlapRotatation()) | |
.frame(idealWidth: 300, idealHeight: 300, alignment: .center) | |
.animation(.spring(.smooth, blendDuration: 0.5), value: progress) | |
.rotation3DEffect( | |
.degrees(180), | |
axis: (x: 0, y: 1, z: 0) | |
) | |
} | |
} | |
func overlapRotatation() -> Angle { | |
let overlapProgress = progress - 1.0 | |
let degrees = overlapProgress * 360.0 | |
return .degrees(-1 * degrees) | |
} | |
} | |
// EXTENSIONS USED |
This file contains hidden or 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
extension Color { | |
func lighter(by percentage: CGFloat = 30.0) -> Color { | |
return self.adjust(by: abs(percentage)) | |
} | |
func darker(by percentage: CGFloat = 30.0) -> Color { | |
return self.adjust(by: -1 * abs(percentage)) | |
} | |
func adjust(by percentage: CGFloat = 30.0) -> Color { | |
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 1.0 | |
#if canImport(UIKit) | |
UIColor(self).getRed(&red, green: &green, blue: &blue, alpha: &alpha) | |
#elseif canImport(AppKit) | |
NSColor(self).getRed(&red, green: &green, blue: &blue, alpha: &alpha) | |
#endif | |
return Color(red: min(red + percentage / 100, 1.0), | |
green: min(green + percentage / 100, 1.0), | |
blue: min(blue + percentage / 100, 1.0), | |
opacity: alpha) | |
} | |
} |
This file contains hidden or 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
struct StackedActivityRingViewConfig { | |
var lineWidth: CGFloat = 15.0 | |
var outterRingColor: Color = .green | |
var middleRingColor: Color = .blue | |
var innerRingColor: Color = .red | |
} | |
struct StackedActivityRingView: View { | |
@Binding var outterRingValue: CGFloat | |
@Binding var middleRingValue: CGFloat | |
@Binding var innerRingValue: CGFloat | |
var config: StackedActivityRingViewConfig = .init() | |
var width: CGFloat = 80.0 | |
var height: CGFloat = 80.0 | |
var body: some View { | |
GeometryReader { geo in | |
ZStack { | |
ActivityRingView(progress: $outterRingValue, mainColor: config.outterRingColor, lineWidth: config.lineWidth) | |
.frame(width: geo.size.width, height: geo.size.height) | |
ActivityRingView(progress: $middleRingValue, mainColor: config.middleRingColor, lineWidth: config.lineWidth) | |
.frame(width: geo.size.width - (2*config.lineWidth), height: geo.size.height - (2*config.lineWidth)) | |
ActivityRingView(progress: $innerRingValue, mainColor: config.innerRingColor, lineWidth: config.lineWidth) | |
.frame(width: geo.size.width - (4*config.lineWidth), height: geo.size.height - (4*config.lineWidth)) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment