CAShapeLayer 的位置不正确

Incorrect position of CAShapeLayer

我有一个叫 viewProgressUIView。它是图像中的白色框。我想要一个圆形的进度条,就是图中的绿色圆圈。进度条应该留在白框内,但如您所见,它离得很远。

如何让它留在 viewProgress 内? 这里有我的动画功能:

func animateView() {

        let circle = viewProgress // viewProgress is a UIView

        var progressCircle = CAShapeLayer()

        let circlePath = UIBezierPath(arcCenter: circle.center, radius: circle.bounds.midX, startAngle: -CGFloat(M_PI_2), endAngle: CGFloat(3.0 * M_PI_2), clockwise: true)

        progressCircle = CAShapeLayer ()
        progressCircle.path = circlePath.CGPath
        progressCircle.strokeColor = UIColor.whiteColor().CGColor
        progressCircle.fillColor = UIColor.clearColor().CGColor
        progressCircle.lineWidth = 10.0

        circle.layer.addSublayer(progressCircle)

        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = 0
        animation.toValue = 0.4
        animation.duration = 1
        animation.fillMode = kCAFillModeForwards
        animation.removedOnCompletion = false

        progressCircle.addAnimation(animation, forKey: "ani")
    }

而我只是在 viewDidLoad()

中调用函数

基本上你没有什么问题:

  1. 图层位置不正确 - 框架应等于父视图中父图层的边界
  2. 你的动画只会播放一次 - 如果你想让它无限播放,请添加类似 animation.repeatCount = MAXFLOAT
  3. 的内容
  4. 确保所有大小正确 - 在 layoutSubviews 中重新创建图层,删除之前创建的图层
  5. UIBezierPath(arcCenter... 将从 rightSide 开始路径,您也可以使用更简单的变体,如 UIBezierPath(ovalInRect。考虑到这一点,如果您想在圆
  6. 的最顶部开始绘图,您还需要为 M_PI_2 旋转图层
  7. 你还应该记住,当线宽为 10 时,你的圆路径的一半将被 parentView 的 clipSubviews 覆盖。为防止这种情况,请使用修改后的 parentLayer rect
  8. 您可能还想提高 lineCap 的可视化效果,购买将其设置为 "round" 样式
  9. 如果您不想从动画中获取完成事件,则不需要
  10. progressCircle.addAnimation(animation, forKey: "ani") 动画键 - 在您的情况下,我看到没有 delegate 并且没有 removeOnCompletion 标志设置为 false , 所以假设你实际上不需要它

记住这一切,代码可以是这样的:

let circle = UIView(frame: CGRectMake(100, 100, 100, 100)) // viewProgress is a UIView
circle.backgroundColor = UIColor.greenColor()
view.addSubview(circle)

var progressCircle = CAShapeLayer()
progressCircle.frame = view.bounds

let lineWidth:CGFloat = 10
let rectFofOval = CGRectMake(lineWidth / 2, lineWidth / 2, circle.bounds.width - lineWidth, circle.bounds.height - lineWidth)

let circlePath = UIBezierPath(ovalInRect: rectFofOval)

progressCircle = CAShapeLayer ()
progressCircle.path = circlePath.CGPath
progressCircle.strokeColor = UIColor.whiteColor().CGColor
progressCircle.fillColor = UIColor.clearColor().CGColor
progressCircle.lineWidth = 10.0
progressCircle.frame = view.bounds
progressCircle.lineCap = "round"

circle.layer.addSublayer(progressCircle)
circle.transform = CGAffineTransformRotate(circle.transform, CGFloat(-M_PI_2))

let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1.1
animation.duration = 1
animation.repeatCount = MAXFLOAT
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)

progressCircle.addAnimation(animation, forKey: nil)

结果实际上是这样的:

注: 如果你想为动画层的旋转设置动画,你还应该在动画组中添加额外的动画