1

I have created some code whereby I animate my custom progressbar.Below is the code I have so far which handles the animation and label.

let animationProgress= CABasicAnimation(keyPath: "strokeEnd")
let value = 0.8
animationProgress.fromValue = 0
animationProgress.toValue = value   (will display 80% of the progressbar)
animationProgress.duration = 1

while value <= 1 {
  DispatchQueue.main.async {
 updateYourUI()
}

}


animationProgress.isRemovedOnCompletion = false 
animationProgress.fillMode = kCAFillModeForwards
shapeLayer.add(animationProgress, forKey: "animated")



func updateYourUI (){
 let value= 50
 view.PercentageComplete.text = "\((value))%"
 view.shapeLayer.strokeEnd = CGFloat(value)

}

How can I get the "let value" display each value from "fromValue" and "toValue " so that they label will display the corresponding value as the progressbar animation is run. I have tried to implement a while loop howerver I am unsure of what condition to place so that it runs for every value from the "animationProgress.fromValue = 0" to the "animationProgress.toValue".

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • Can you post the code where you define `percentage` and any other code that might be relevant? Is this code in ViewController or a custom class? – Chris May 19 '18 at 09:52
  • What you have here will simply animate the stroke to 0.8 over 1 second. I think you have to set up a delegate for the animation to observe its progress. I will have a look for a solution. In the last line, should `LayerShape` not be `shapeLayer`? – Chris May 19 '18 at 10:04
  • notice that your while loop is endless :) – Björn Ro May 19 '18 at 10:07
  • Here is a link to a solution for tracking progress of an animation: https://stackoverflow.com/a/35189336 – Chris May 19 '18 at 10:17
  • @Chris I have just noticed that there were some mistakes within the code. This has been fixed. The value variable is the one which contains how much of the progressbar will be covered. My full code contains 1 method which contains all details about progress track/ shapeLayer/ animatedprogress. I am using swift 3 so am quite confused of how to implement your given solution. – user9815047 May 19 '18 at 10:37
  • @Chris Also I have read that the "DispatchQueue.main.async {}" should run everytime aslong as the value is not equal to 0.8 therefore the output should display the label changing with the progressbar. Eg 0% , 0.1% and so on until it reaches 0.8 where the loop stops. – user9815047 May 19 '18 at 10:37
  • @BjörnRo I am clear that the loop is endless as I am not sure what condition to use so that the "DispatchQueue.main.async {}" will keep running and updating the label inside that method until the value gets to 0.8 – user9815047 May 19 '18 at 10:38
  • just check my answer. there is all u need. u can remove the loop and updateFunc function – Björn Ro May 19 '18 at 10:40

1 Answers1

1

u can check the animation state of the layer. I used the DisplayLink approach

@IBOutlet weak var percentageLabel: UILabel!    
let loadingDisplayLink: CADisplayLink?
let shapeLayer: CAShapeLayer?

// in your viewDidAppear for example
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let displaylink = CADisplayLink(target: self, selector: #selector(updateLabel))
    displaylink.add(to: .current,
                    forMode: .defaultRunLoopMode)
    loadingDisplayLink = displayLink
}

func updateLabel(displayLink: CADisplayLink) {
    if let layer = shapeLayer {
        let percent: CGFloat = layer.presentation()?.value(forKeyPath: "strokeEnd") as? CGFloat ?? 0.0
        percentageLabel.text = String(format: "%.f%%", percent * 100)

        if percent >= 1 {
            displayLink.invalidate()
            loadingDisplayLink = nil
        }
    }
}

To explain what CADisplayLink does. It guaranties that u get a function call for every frame that is really changed in the complete Window. So u can be sure, that u dont miss a frame und doe something on every framechange

Björn Ro
  • 780
  • 3
  • 9