ios - 在圆形路径上为 CAShapeLayer 设置动画

标签 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")

最佳答案

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

由于您在执行其中任何一项时遇到困难,让我们尝试一种不同的方法。看看标准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

关于ios - 在圆形路径上为 CAShapeLayer 设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52867310/

相关文章:

swift - 如何根据任何项是否为空将可空项数组转换为可为空数组?

swift - 当窗口关闭然后选择另一个应用程序时,Mac 应用程序消失

ios - 为什么一个 View Controller 创建了两次?

ios - 更改 slider 上的动画速度

ios - 模拟一个 "picture taken"的屏幕闪

iphone - UIFont Woes(一些自定义字体加载,但其他的不是)

ios - UIViewPropertyAnimator 在呈现另一个 Controller 后停止工作

javascript - 使用 stringByEvaluatingJavaScriptFromString document.getElementsByClassName 从 UIWebView 获取数据

ios - 创建一个图层,其中一些按钮可以工作?

java - Objective-C 中 Java ArrayList 的等价物