I am using an arc for a progress bar.
There is a track layer that the progress indicator moves along and I also have a circle that moves with the progress bar for added emphasis. Both the progress bar and the circle move correctly along the path but when the progress is complete, instead of stopping at the end of the path, the circle jumps back to the beginning of the progress path.
The code:
class ViewController: UIViewController {
let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()
let dotLayer: CALayer = CALayer()
let seconds = 10.0
// MARK: - Properties
private var progressBarView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
title = "Making Progress"
view.backgroundColor = .systemTeal
// determine the value of Center
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: 2.7, endAngle: 0.45, clockwise: true) // these values give us a complete circle
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.lightGray.cgColor
trackLayer.lineWidth = 10
trackLayer.fillColor = UIColor.clear.cgColor
trackLayer.lineCap = .round
view.layer.addSublayer(trackLayer)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10
shapeLayer.strokeEnd = 0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = .round
view.layer.addSublayer(shapeLayer)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap )))
}
@objc private func handleTap() {
print("Attempting to animate stroke")
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = 1
basicAnimation.duration = seconds
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation, forKey: "anyKeyWillDo")
// circle image
let circleNobImage = UIImage(named: "whiteCircle.png")!
dotLayer.contents = circleNobImage.cgImage
dotLayer.bounds = CGRect(x: 0.0, y: 0.0, width: circleNobImage.size.width, height: circleNobImage.size.height)
view.layer.addSublayer(dotLayer)
dotLayer.position = CGPoint(x: 105, y: 460)
dotLayer.opacity = 1
dotAnimation()
}
func dotAnimation() {
let dotAnimation = CAKeyframeAnimation(keyPath: "position")
dotAnimation.path = trackLayer.path
dotAnimation.calculationMode = .paced
let dotAnimationGroup = CAAnimationGroup()
dotAnimationGroup.duration = seconds
dotAnimation.autoreverses = false
dotAnimationGroup.animations = [dotAnimation]
dotLayer.add(dotAnimationGroup, forKey: nil)
}
}
I need to get the circle to stop at the end of the arc with the progress bar. How is this done?
Also set dotAnimationGroup.fillMode
and dotAnimationGroup.isRemovedOnCompletion
dotAnimationGroup.fillMode = .forwards
dotAnimationGroup.isRemovedOnCompletion = false