对于大于PI的值,CAKeyFrameAnimation不是线性的

时间:2017-02-10 11:29:35

标签: ios swift swift3 core-animation cakeyframeanimation

我很难理解为什么动画没有像预期的那样工作。 我在做的是:

  1. 使用圆弧创建UIBezierPath以沿此路径移动标签并为路径描边设置动画。

    //Start Point is -.pi /2 to let the Arc start at the top.
    //self.progress = Value between 0.0 and 1.0
    let path : UIBezierPath = UIBezierPath.init(arcCenter: CGPoint.init(x: self.bounds.width * 0.5, y: self.bounds.height * 0.5), 
    radius: self.bounds.width * 0.5, startAngle: -.pi / 2, endAngle: (2 * self.progress * .pi) - (.pi / 2), clockwise: true)
    return path
    
  2. 将此路径添加到CAShapeLayer

    circlePathLayer.frame = bounds
    circlePathLayer.path = self.path.cgPath
    circlePathLayer.strokeStart = 0
    circlePathLayer.strokeEnd = 1
    
  3. 使用CABasicAnimation

    为strokeEnd属性设置动画
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.repeatCount = HUGE
    animation.fromValue = 0.0
    animation.toValue = 1.0
    animation.duration = self.animationDuration
    animation.isRemovedOnCompletion = false
    animation.fillMode = kCAFillModeBoth
    
  4. 使用CAKeyFrameAnimation

    为我的标签的位置属性设置动画
    let animationScore = CAKeyframeAnimation(keyPath: "position")
    //some things I tried to fix
    //animationScore.timingFunctions = [CAMediaTimingFunction(controlPoints: 0.250, 0.250, 0.750, 0.750)]
    //animationScore.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear)
    animationScore.path = self.path.cgPath
    animationScore.duration = self.animationDuration
    animationScore.isRemovedOnCompletion = false
    animationScore.fillMode = kCAFillModeBoth
    animationScore.repeatCount = HUGE
    
  5. 将我的动画添加到图层和标签

    self.circlePathLayer.add(animation, forKey: nil)
    self.scoreLabel.layer.add(animationScore, forKey: nil)
    
  6. 我的问题:对于大于0.75的ProgressValues,我的标签没有以线性速度移动。值大于0.75表示我的弧大于PI。 对于小于0.75的值,我的动画工作正常,标签和strokeend具有相同的速度,并且彼此重叠。

    GIF:      Gif showing the animation

    请忽略此gif中标签中的100%,我的进度值为0.76。

    你看到我的标签在我的四分之三圈后减慢了。

    我希望有人可以帮助我。 非常感谢

1 个答案:

答案 0 :(得分:5)

关键帧动画引入了不必要的复杂功能。只需围绕中心旋转标签,其持续时间与形状图层的笔触动画相同:

enter image description here

(我很抱歉我的动画从底部开始,而不是顶部,但是当我编写代码时我没有看你的问题,现在我懒得改变它!)

那么,这是怎么做到的?它是三个动画,都具有相同的持续时间:

  • 形状图层strokeEnd,与动画类似。

  • 穿过圆心的“手臂”,标签作为一端的子层(使标签出现在圆的半径)。手臂进行旋转变换动画。

  • 标签以相反方向执行旋转变换动画。如果没有,它将与其超级层一起旋转。 (想想摩天轮是如何工作的;你的椅子在手臂的末端,但它相对于地球保持直立。)

这是整个动画代码:

    let anim = CABasicAnimation(keyPath: "transform.rotation.z")
    anim.fromValue = 0
    anim.toValue = 5
    anim.duration = 10
    self.arm.layer.add(anim, forKey:nil)

    let anim2 = CABasicAnimation(keyPath: "transform.rotation.z")
    anim2.fromValue = 0
    anim2.toValue = -5
    anim2.duration = 10
    self.lab.layer.add(anim2, forKey:nil)

    let anim3 = CABasicAnimation(keyPath: "strokeEnd")
    anim3.fromValue = 0
    anim3.toValue = 1
    anim3.duration = 10
    self.shape.add(anim3, forKey:nil)