圆形路径中的动画线形CAShapeLayer

时间:2019-07-23 06:01:47

标签: ios swift cashapelayer cabasicanimation

我正在尝试沿圆形路径为线形CAShapeLayer设置动画。我创建了线层的初始路径和最终路径,并将它们添加到CABasicAnimation的值中。

但是动画不是我所期望的。我在这里停留了过去两天。

func getAllLayers() -> [CALayer] 

   {

    var layers = []

    let pointerEndPoint = CGPoint(x: xPointOfPointer , y: yPointOfPointer)  // Final end point of pointer
    let radius = 5

    let pointerFinalPath = UIBezierPath()
    pointerFinalPath.addArc(withCenter: circleCenter, radius: radius, startAngle: 0, endAngle:2 * CGFloat.pi, clockwise: false)
    pointerFinalPath.move(to: circleCenter)
    pointerFinalPath.addLine(to: endPoint)
    pointerFinalPath.close()

    let pointerPathLayer = CAShapeLayer()
    pointerPathLayer.path = pointerFinalPath.cgPath
    pointerPathLayer.lineWidth = 2
    pointerPathLayer.fillColor = UIColor.black.cgColor
    pointerPathLayer.strokeColor = UIColor.black.cgColor
    layers.append(pointerPathLayer)

    let pointerInitialBezierPath = UIBezierPath()
    pointerInitialBezierPath.addArc(withCenter: circleCenter, radius: radius,startAngle: 0 , endAngle: 2 * CGFloat.pi , clockwise: false)
    pointerInitialBezierPath.move(to: circleCenter)
    pointerInitialBezierPath.addLine(to: CGPoint(x: circleCenter.x - 50 , y: centerY))
    pointerInitialBezierPath.close()


    let pointerInitialCGPath = pointerInitialBezierPath.cgPath
    let pointerFinalCGPath = pointerFinalPath.cgPath


                    // Pointer Animation
    let pointerAnimation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.path))
     pointerAnimation.fromValue = pointerInitialCGPath
     pointerAnimation.toValue = pointerFinalCGPath
      pointerAnimation.duration = 0.5
      pointerAnimation.isCumulative = true
      pointerPathLayer.add(pointerAnimation, forKey: "Animation")

return layers
}

在Stack over流中搜索解决方案,但找不到我的错误。我希望动画能像时钟一样转动。

My Animation

请注意,随着动画的进行,针的长度也在变化。我希望它保持恒定的长度,只希望改变针的角度。我将不胜感激。

编辑1:如果我尝试transform.rotation动画使针头旋转,但发生在错误的中心点附近。

      // Pointer Animation

            let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
            rotateAnimation.fromValue = 0.0
            rotateAnimation.toValue = angleOfActualValueinRad
            rotateAnimation.duration = 2.0
            pointerPathLayer.add(rotateAnimation, forKey: "Animation")

Roatation Animation

编辑2:使用此链接找到我的github项目。 Animation Issue

3 个答案:

答案 0 :(得分:1)

您使用了错误的变换旋转,请尝试执行以下操作

let rAnimation = CABasicAnimation(keyPath:"transform.rotation.z")
    rAnimation.duration = 1
    rAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    rAnimation.fromValue = degree2radian(90)
    rAnimation.repeatCount = Float.infinity
    rAnimation.toValue = degree2radian(180)
    progressLineLayer.add(rAnimation, forKey:"rotate")

func degree2radian(_ a: CGFloat) -> CGFloat {
    return CGFloat.pi * a / 180
}

通过此链接http://sketchytech.blogspot.com/2014/11/swift-how-to-draw-clock-face-using_12.html查看,也许会有所帮助

已更新:

我写了一些代码来演示其工作原理

private func animateProgress() {

    // black circle at center

    let blackCirclePath = UIBezierPath()
    blackCirclePath.addArc(withCenter: view.center, radius: 5, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
    blackCirclePath.fill()
    UIColor.black.setFill()
    blackCirclePath.close()

    let circleLayer = CAShapeLayer()
    circleLayer.path = blackCirclePath.cgPath
    view.layer.addSublayer(circleLayer)

    // all scale gray background layer

    let grayHalfCirclePath = UIBezierPath()
    grayHalfCirclePath.addArc(withCenter: view.center, radius: 50, startAngle: 0, endAngle: CGFloat.pi, clockwise: false)

    let grayHalfCircleLayer = CAShapeLayer()
    grayHalfCircleLayer.frame = view.bounds
    grayHalfCircleLayer.path = grayHalfCirclePath.cgPath
    grayHalfCircleLayer.strokeColor = UIColor.lightGray.cgColor
    grayHalfCircleLayer.fillColor = nil
    grayHalfCircleLayer.lineWidth = 10
    view.layer.addSublayer(grayHalfCircleLayer)

    // animated progress scale

    let progressHalfCirclePath = UIBezierPath()
    progressHalfCirclePath.addArc(withCenter: view.center, radius: 50, startAngle: CGFloat.pi, endAngle: -CGFloat.pi / 2, clockwise: true)

    let progressLayer = CAShapeLayer()
    progressLayer.frame = view.bounds
    progressLayer.path = progressHalfCirclePath.cgPath
    progressLayer.strokeColor = UIColor.orange.cgColor
    progressLayer.fillColor = nil
    progressLayer.lineWidth = 10
    view.layer.addSublayer(progressLayer)

    // animation

    let pAnimation = CABasicAnimation(keyPath: "strokeEnd")
    pAnimation.duration = 1.0
    pAnimation.fromValue = NSNumber(floatLiteral: 0)
    pAnimation.toValue = NSNumber(floatLiteral: 1)
    progressLayer.add(pAnimation, forKey: "strokeEnd")

    // black arrow

    let progressLineLayer = CAShapeLayer()
    progressLineLayer.frame = view.bounds

    let progressLinePath = CGMutablePath()
    progressLinePath.move(to: CGPoint(x: view.center.x, y: view.center.y))
    progressLinePath.addLine(to: CGPoint(x: view.center.x - 30, y: view.center.y - 30))
    progressLineLayer.path = progressLinePath
    progressLineLayer.strokeColor = UIColor.green.cgColor
    progressLineLayer.lineWidth = 1
    progressLineLayer.strokeColor = UIColor.black.cgColor
    view.layer.addSublayer(progressLineLayer)

    let rAnimation = CABasicAnimation(keyPath:"transform.rotation.z")
    rAnimation.duration = 1
    rAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    rAnimation.fromValue = degree2radian(-45)
    rAnimation.repeatCount = 1
    rAnimation.toValue = degree2radian(45)
    progressLineLayer.add(rAnimation, forKey:"rotate")
}

func degree2radian(_ a: CGFloat) -> CGFloat {
    return CGFloat.pi * a / 180
}

答案 1 :(得分:0)

尝试这个图书馆 ABGuageViewKit

重量轻,可通过动画进行自定义。

希望这对您有所帮助,并且编码愉快。

答案 2 :(得分:0)

您无法使用UIBezierPath实现速度计动画。 您需要以任何角度变换Line。 请参考以下代码,我只为解决您的问题而进行了轮换。

let circleCenter = CGPoint(x: 150.0, y: 150.0)

let startPoint = CGPoint(x: 100, y: 150.0)
    // Start Path
    let pointerStartPath = UIBezierPath()
    pointerStartPath.move(to: circleCenter)
    pointerStartPath.addLine(to: startPoint)
    pointerStartPath.close()

    let pointerPathLayer = CAShapeLayer()
    pointerPathLayer.frame = CGRect(x: 0, y:0, width: 300, height: 300)
    pointerPathLayer.path = pointerStartPath.cgPath
    pointerPathLayer.lineWidth = 2
    pointerPathLayer.fillColor = UIColor.green.cgColor
    pointerPathLayer.strokeColor = UIColor.black.cgColor
    self.view.layer.addSublayer(pointerPathLayer)

    let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
    rotateAnimation.fromValue = 0.0
    rotateAnimation.toValue = CGFloat.pi * 2.0
    rotateAnimation.duration = 2.0
    pointerPathLayer.add(rotateAnimation, forKey: "Animation")

使用此代码,可以实现360度旋转。