在圆形路径上动画CAShapeLayer

时间:2018-10-18 05:03:55

标签: ios swift calayer cashapelayer caanimation

我想为绘制的路径上的拇指层设置动画。我可以根据该值对进度层进行动画处理,但是移动整个层是行不通的。

enter image description here

func setProgress(_ value:Double, _ animated :Bool) {
    let progressAnimation = CABasicAnimation(keyPath: "strokeEnd")
    progressAnimation.duration = animated ? 0.6 : 0.0
    progressAnimation.fromValue = currentValue
    progressAnimation.toValue = value
    progressAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    progressLayer.strokeEnd = CGFloat(value)
    progressLayer.add(progressAnimation, forKey: "animateprogress")
}

使用此功能,我可以为进度层设置动画。而且我被困在动画拇指位置。

我尝试了一些操作,但是没有用。

尝试失败1

    guard let path = thumbLayer.path else {return}
    let center = CGPoint(x: frame.width/2, y: frame.height/2)
    let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
    let thumbAngle = 2 * .pi * currentValue - (.pi/2)
    let thumbX = CGFloat(cos(thumbAngle)) * radius
    let thumbY = CGFloat(sin(thumbAngle)) * radius
    let newThumbCenter = CGPoint(x: center.x + thumbX, y: center.y + thumbY)
    let thumbPath = UIBezierPath(arcCenter: newThumbCenter, radius: thumbWidth/2, startAngle: -.pi/2, endAngle: .pi*1.5, clockwise: true)

    let thumbAnimation = CABasicAnimation(keyPath: "path")
    thumbAnimation.duration = animated ? 0.6 : 0.0
    thumbAnimation.fromValue = path
    thumbAnimation.toValue = thumbPath.cgPath
    thumbAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.strokeEnd = CGFloat(value)
    thumbLayer.add(thumbAnimation, forKey: "animateprogress")

尝试失败2

    let intialPosition = thumbLayer.position
    let center = CGPoint(x: frame.width/2, y: frame.height/2)
    let radius = min(frame.width, frame.height)/2 - max(trackWidth, max(progressWidth, thumbWidth))/2
    let thumbAngle = 2 * .pi * currentValue - (.pi/2)
    let thumbX = CGFloat(cos(thumbAngle)) * radius
    let thumbY = CGFloat(sin(thumbAngle)) * radius
    let newThumbCenter = CGPoint(x: center.x + thumbX - thumbCenter.x, y: center.y + thumbY - thumbCenter.y)

    thumbLayer.position.x = newThumbCenter.x
    let thumbAnimationX = CABasicAnimation(keyPath: "progress.x")
    thumbAnimationX.duration = animated ? 0.6 : 0.0
    thumbAnimationX.fromValue = intialPosition.x
    thumbAnimationX.toValue = newThumbCenter.x
    thumbAnimationX.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.add(thumbAnimationX, forKey: "progress.x")


    thumbLayer.position.y = newThumbCenter.y
    let thumbAnimationY = CABasicAnimation(keyPath: "progress.y")
    thumbAnimationY.duration = animated ? 0.6 : 0.0
    thumbAnimationY.fromValue = intialPosition.y
    thumbAnimationY.toValue = newThumbCenter.y
    thumbAnimationY.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    thumbLayer.add(thumbAnimationY, forKey: "progress.y")

1 个答案:

答案 0 :(得分:7)

在您的第一次尝试中,您试图为拇指的路径(红色圆圈的轮廓)设置动画。第二次尝试是为position中的thumbLayer设置动画(但您设置了错误的关键路径动画)。

由于您在进行任何一项工作时都遇到困难,因此让我们尝试另一种方法。看看标准的Swiss railway clock

Swiss railway clock

具体来说,请看秒针末端的红点。时钟如何在脸上移动红点?通过绕着脸部中心旋转秒针。

这就是我们要做的,但是我们不会抽整张秒针。我们将在最后画一个红点。

我们将thumbLayer的坐标系的原点放置在圆形轨迹的中心,并设置其路径,以使拇指出现在路径上。这是布局:

layout

这里是设置circleLayerthumbLayer的代码:

    private let circleLayer = CAShapeLayer()
    private let thumbLayer = CAShapeLayer()

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        let circleRadius: CGFloat = 100
        let thumbRadius: CGFloat = 22
        let circleCenter = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

        circleLayer.fillColor = nil
        circleLayer.strokeColor = UIColor.black.cgColor
        circleLayer.lineWidth = 4
        circleLayer.lineJoin = .round
        circleLayer.path = CGPath(ellipseIn: CGRect(x: -circleRadius, y: -circleRadius, width: 2 * circleRadius, height: 2 * circleRadius), transform: nil)
        circleLayer.position = circleCenter
        view.layer.addSublayer(circleLayer)

        thumbLayer.fillColor = UIColor.red.cgColor
        thumbLayer.strokeColor = nil
        thumbLayer.path = CGPath(ellipseIn: CGRect(x: -thumbRadius, y: -circleRadius - thumbRadius, width: 2 * thumbRadius, height: 2 * thumbRadius), transform: nil)
        thumbLayer.position = circleCenter
        view.layer.addSublayer(thumbLayer)
    }

使用此布局,我们可以沿轨迹移动拇指而无需更改其位置。相反,我们绕其原点旋转thumbLayer

    @IBAction func buttonWasTapped() {
        let animation = CABasicAnimation(keyPath: "transform.rotation")
        animation.fromValue = 0
        animation.toValue = 2 * CGFloat.pi
        animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        animation.duration = 1.5
        animation.isAdditive = true
        thumbLayer.add(animation, forKey: nil)
    }

结果:

demo