I'm trying to animate the progress bar in the SwiftUI progress view. I found something that can help for this but in UIProgressView however I trying to accomplish this with SwiftUI. Current approach:
ProgressView(value: 0.25).animation(Animation.easeInOut(duration: 3))
The problem with this is the whole view is being animated. I want only the progress bar animated.
I found a solution for this
@State private var counter = 0.0
var body: some View {
ProgressView(value: counter, total: 100.0)
.onAppear {
self.runCounter(counter: self.$counter, start: 0.0, end: 50.0, speed: 0.05)
}
}
func runCounter(counter: Binding<Double>, start: Double, end: Double, speed: Double) {
counter.wrappedValue = start
Timer.scheduledTimer(withTimeInterval: speed, repeats: true) { timer in
counter.wrappedValue += 1.0
if counter.wrappedValue == end {
timer.invalidate()
}
}
}
This is a custom animation, it is not the final version or even final code but it would solve your issue,
struct ContentView: View {
@State private var value: CGFloat = 0.5
@State private var valueAnimation: CGFloat = CGFloat()
@State private var qualityOfAnimation: Quality = .excellent
@State private var duration: Double = 5.0
var body: some View {
VStack(spacing: 30.0) {
Text(String(describing: qualityOfAnimation) + " Quality").bold()
ProgressView(value: valueAnimation)
.customAnimation(value: value, valueAnimation: $valueAnimation, duration: duration, qualityOfAnimation: qualityOfAnimation)
Button("update to 1.0") { value = 1.0 }
Button("update to 0.0") { value = 0.0 }
Button("update to slow Quality") { qualityOfAnimation = .slow }
Button("update to excellent Quality") { qualityOfAnimation = .excellent }
HStack { Text("Duration:").bold().fixedSize(); Slider(value: $duration,in: 0.0...10.0); Text(duration.rounded + " sec").bold().frame(width: 80).fixedSize() }
}
.padding()
}
}
struct CustomAnimationViewModifier: ViewModifier {
var value: CGFloat
@Binding var valueAnimation: CGFloat
var duration: Double
var qualityOfAnimation: Quality
init(value: CGFloat, valueAnimation: Binding<CGFloat>, duration: Double, qualityOfAnimation: Quality) {
self.value = value
self._valueAnimation = valueAnimation
self.duration = duration
self.qualityOfAnimation = qualityOfAnimation
}
func body(content: Content) -> some View {
return content
.onAppear() { valueAnimation = value }
.onChange(of: value) { [value] newValue in
let millisecondsDuration: Int = Int(duration * 1000)
let tik: Int = qualityOfAnimation.rawValue
let step: CGFloat = (newValue - value)/CGFloat(millisecondsDuration/tik)
valueAnimationFunction(tik: tik, step: step, value: newValue, increasing: step > 0.0 ? true : false)
}
}
func valueAnimationFunction(tik: Int, step: CGFloat, value: CGFloat, increasing: Bool) {
if increasing {
if valueAnimation + step < value {
valueAnimation += step
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(tik)) {
valueAnimationFunction(tik: tik, step: step, value: value, increasing: increasing)
}
}
else {
valueAnimation = value
}
}
else {
if valueAnimation + step > value {
valueAnimation += step
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(tik)) {
valueAnimationFunction(tik: tik, step: step, value: value, increasing: increasing)
}
}
else {
valueAnimation = value
}
}
}
}
extension View {
func customAnimation(value: CGFloat, valueAnimation: Binding<CGFloat>, duration: Double, qualityOfAnimation: Quality = Quality.excellent) -> some View {
return self.modifier(CustomAnimationViewModifier(value: value, valueAnimation: valueAnimation, duration: duration, qualityOfAnimation: qualityOfAnimation))
}
}
enum Quality: Int, CustomStringConvertible {
case excellent = 1, high = 10, basic = 100, slow = 1000
var description: String {
switch self {
case .excellent: return "excellent"
case .high: return "high"
case .basic: return "basic"
case .slow: return "slow"
}
}
}
extension Double { var rounded: String { get { return String(Double(self*100.0).rounded()/100.0) } } }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.