Last active
April 17, 2021 16:48
-
-
Save sledsworth/67528bfc04a630cf8d5a9147bb9c514d to your computer and use it in GitHub Desktop.
Generic Animated Progress Bar in SwiftUI
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
import Foundation | |
import UIKit | |
import SwiftUI | |
import Combine | |
class NutrientModel: Progressable { | |
var willChange = PassthroughSubject<BaseNutrient, Never>() | |
var id = UUID.init() | |
var name: String | |
var description: String { | |
get { | |
return "\(current) / \(total)" | |
} | |
} | |
var current: CGFloat | |
var total: CGFloat | |
var progress: CGFloat { | |
get { | |
return current / total | |
} | |
} | |
var gradient: LinearGradient | |
init(name: String, unit: NutrientUnit, total: CGFloat, colors: [Color] = [Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255), Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)], start: CGFloat = 0) { | |
self.name = name | |
self.total = total | |
self.current = start | |
self.gradient = LinearGradient(gradient: .init(colors: colors), startPoint: .init(x: 0.0, y: 0), | |
endPoint: .init(x: 1.0, y: 0)) | |
} | |
func addProgress(_ progress: CGFloat) { | |
willChange.send(self) | |
self.current += progress | |
} | |
func removeProgress(_ progress: CGFloat) { | |
willChange.send(self) | |
self.current -= progress | |
if self.current < 0 { | |
self.current = 0 | |
} | |
} | |
} |
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
import SwiftUI | |
protocol Progressable: ObservableObject { | |
/// Name of the progressable field | |
var name: String { get } | |
/// The text form of the progress being made (ex. formatted percentage or fraction) | |
var description: String { get } | |
/// The percentage of progress made as float | |
var progress: CGFloat { get } | |
/// The linear gradient use to fill the completed portion of the bar | |
var gradient: LinearGradient { get set } | |
} |
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
import SwiftUI | |
struct ProgressBarComponent<P: Progressable> : View { | |
@ObservedObject var progression: P | |
var progressAnimation: Animation { | |
Animation | |
.interpolatingSpring(mass: 43, stiffness: 3.2, damping: 0.5) | |
.speed(3) | |
.delay(0.07) | |
} | |
var barHeight: CGFloat = 12.0 | |
var body: some View { | |
VStack { | |
HStack { | |
Text(self.progression.name) | |
.font(.subheadline) | |
.foregroundColor(.gray) | |
Spacer() | |
Text(self.progression.description) | |
.font(.subheadline) | |
.foregroundColor(.gray) | |
} | |
.padding(.bottom, -8) | |
.padding(.horizontal, 4) | |
ZStack { | |
GeometryReader { geometry in | |
RoundedRectangle(cornerRadius: 100.0) | |
.fill( | |
Color(.displayP3, | |
red: 150 / 255, | |
green: 150 / 255, | |
blue: 150 / 255, | |
opacity: 0.1) | |
) | |
.overlay( | |
RoundedRectangle(cornerRadius: 100.0) | |
.size( | |
width: max(geometry.size.width * self.progression.progress, self.barHeight), | |
height: geometry.size.height) | |
.fill(self.progression.gradient) | |
.animation(self.progressAnimation) | |
) | |
} | |
} | |
.frame(height: self.barHeight, alignment: .leading) | |
} | |
} | |
} |
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
import SwiftUI | |
struct DayProgressContainer : View { | |
var trackedNutreints: [NutrientModel] | |
var body: some View { | |
return VStack { | |
ForEach(self.trackedNutreints, id: \.self) { nutrient in | |
ProgressBarComponent(progression: nutrient) | |
.padding(.vertical, 4) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!