WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Circular Progress Bar - Animate progress change

Forums > iOS

Hi, I am trying to make custom circular progress bar. So far, I can animate progress filling status from 0 to some value (lets say 30), but when the value is changed (lets say to 60) I dont want progress status to be animated from 0 to 60, but from 30 to 60.

Here is my animation code - I'm actually adding another sublayer to the original one...

    private var progressLayer = CAShapeLayer()
    private var progressValue: Int = 0;

    ///
    func updateProgressPath() {
        let progressValueRadians = startPoint + CGFloat(progressValue) * 3.6 * CGFloat.pi/180.0
        let progressPath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: radius, startAngle: startPoint, endAngle: progressValueRadians, clockwise: true)

        // progressLayer path defined to circularPath
        progressLayer.path = progressPath.cgPath
        // ui edits
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.lineCap = .butt
        progressLayer.lineWidth = radius * barWidthPercentage
        progressLayer.strokeEnd = 0
        progressLayer.strokeColor = progressBarColorDone
        // added progressLayer to layer
        layer.addSublayer(progressLayer)
    }

    ///
    func progressAnimation(duration: TimeInterval) {
        // created circularProgressAnimation with keyPath
        let circularProgressAnimation = CABasicAnimation(keyPath: "strokeEnd")
        // set the end time
        circularProgressAnimation.duration = duration
        circularProgressAnimation.toValue = 1.0
        circularProgressAnimation.fillMode = .forwards
        circularProgressAnimation.isRemovedOnCompletion = false
        progressLayer.add(circularProgressAnimation, forKey: "progressAnim")
    }

    ///
    func setValue(to value: Int) {
        if value > 100 || value < 0 {
            progressValue = 0
            return
        }
        progressValue = value
        updateProgressPath()
        progressAnimation(duration: 1)
    }

2      

Hi iLomidze

If you doing this in SwiftUI. You can do this

struct ProgressRing: View {
    @Binding var progress: Double

    private var formattedPercent: String {
        let formatter = NumberFormatter()
        formatter.maximumFractionDigits = 1
        formatter.numberStyle = .percent
        return formatter.string(from: NSNumber(value: progress)) ?? ""
    }

    var body: some View {
        ZStack {
            Circle()
                .stroke(Color.black, lineWidth: 24)

            Text(formattedPercent)
                .font(.system(size: 64))

            Circle()
                .trim(from: 0.0, to: CGFloat(progress))
                .stroke(Color.blue, style: StrokeStyle(lineWidth: 13, lineCap: .round))
                .rotationEffect(.degrees(-90))
        }
        .padding(30)
        .onTapGesture {
            withAnimation {
                progress = min(1.0, progress + 0.125)
            }
        }
    }
}

then can use it in the view

struct ContentView: View {
    @State var progress: Double = 0.25

    private var formattedPercent: String {
        let formatter = NumberFormatter()
        formatter.maximumFractionDigits = 1
        formatter.numberStyle = .percent
        return formatter.string(from: NSNumber(value: progress)) ?? ""
    }

    var body: some View {
        VStack {
            Slider(value: $progress)
                .padding()
            ProgressRing(progress: $progress)
                .frame(width: 300, height: 300)
        }
    }
}

2      

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.