简体   繁体   中英

Animating processbar in ProgressView SwiftUI

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM