Ios 在圆形路径中设置线状层的动画

Ios 在圆形路径中设置线状层的动画,ios,swift,cashapelayer,cabasicanimation,Ios,Swift,Cashapelayer,Cabasicanimation,我正试图沿着一条圆形路径设置我的线状CAShapeLayer的动画。我创建了线条图层的初始路径和最终路径,并将它们添加到CABasicAnimation的from和to值中 然而,动画不是我所期望的。我在这里呆了两天 func getAllLayers() -> [CALayer] { var layers = [] let pointerEndPoint = CGPoint(x: xPointOfPointer , y: yPointOfPointer)

我正试图沿着一条圆形路径设置我的线状CAShapeLayer的动画。我创建了线条图层的初始路径和最终路径,并将它们添加到CABasicAnimation的from和to值中

然而,动画不是我所期望的。我在这里呆了两天

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
}
在堆栈溢出中搜索解决方案,但找不到我的错误。我希望我的动画像时钟的指针一样移动

请注意,随着动画的进行,针的长度正在更改。我希望它保持恒定的长度,只希望我的针的角度改变。我将非常感谢任何帮助

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

编辑2:使用此链接查找我的github项目

试试这个库

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


希望这有助于实现愉快的编码。

使用UIBezierPath无法实现速度表动画。 您需要以任意角度变换直线。 请参考下面的代码旋转,我只是为了解决你的问题

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)

// New : Set Anchor point
pointerPathLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)

    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º旋转。

如果使用了错误的变换旋转,请尝试这样做smth

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
}
看看这个链接,可能会有帮助

更新:

我写了一些代码来说明它是如何工作的

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
}

谢谢你抽出时间。你知道为什么我的代码不起作用吗?如果你改变
pointerPathLayer
anchorPoint
,改为添加旋转动画怎么办?我用旋转代码发布答案。@girish\u pro问题更新你需要设置锚定点。检查我的答案。添加以下行。pointerPathLayer.ancorpoint=CGPoint(x:0.5,y:0.5)人们感谢您的帮助和时间。这里的问题是我没有为CAShapeLayer设置框架。这种做法是在UIView中使用约束的结果。因此,正如@girish_pro所建议的,我通过正确地为每个CAShapelayer计算框架,并在我的CABASICANIATION中从角度值和角度值应用来修复它。仍然是相同的问题吗?是的,兄弟,请检查我随附的git项目,它显示了这个问题。谢谢你的帮助。我真的很感谢你抽出时间来帮助我。