【问题标题】:animate CAShapeLayer on circular path在圆形路径上为 CAShapeLayer 设置动画
【发布时间】:2019-03-22 20:48:09
【问题描述】:

我想在绘制的路径上为我的拇指图层设置动画。我可以根据值为进度层设置动画,但是移动整个层不起作用。

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

【问题讨论】:

    标签: ios swift calayer cashapelayer caanimation


    【解决方案1】:

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

    由于您在完成其中任何一项工作时遇到困难,让我们尝试不同的方法。看看标准Swiss railway clock

    具体看秒针末端的红点。时钟如何移动脸部周围的那个红点?通过围绕脸部中心旋转秒针。

    这就是我们要做的,但我们不会画出整个秒针。我们只画最后的红点。

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

    这是设置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)
        }
    

    结果:

    【讨论】:

    • 如果我在中点停止旋转。拇指移回原来的位置。我需要设置拇指的位置吗?
    • 通过将图层的affineTransform设置为合适的旋转矩阵来设置拇指的位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多