如何为 CAKeyFrameAnimation 设置端点?

How do I set an endpoint for a CAKeyFrameAnimation?

我正在使用圆弧作为进度条。

有一个进度指示器移动的轨道层,我还有一个随着进度条移动的圆圈,以增加强调。进度条和圆圈都沿着路径正确移动,但是当进度完成时,圆圈不会停在路径的末尾,而是跳回到进度路径的开头。

screen recording of behavior

代码:

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)
    }
}

我需要让圆圈停止在带有进度条的圆弧末端。这是怎么做到的?

同时设置 dotAnimationGroup.fillModedotAnimationGroup.isRemovedOnCompletion

dotAnimationGroup.fillMode = .forwards
dotAnimationGroup.isRemovedOnCompletion = false