CAShapeLayer 的位置不正确
Incorrect position of CAShapeLayer
我有一个叫 viewProgress
的 UIView
。它是图像中的白色框。我想要一个圆形的进度条,就是图中的绿色圆圈。进度条应该留在白框内,但如您所见,它离得很远。
如何让它留在 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()
中调用函数
基本上你没有什么问题:
- 图层位置不正确 - 框架应等于父视图中父图层的边界
- 你的动画只会播放一次 - 如果你想让它无限播放,请添加类似
animation.repeatCount = MAXFLOAT
的内容
- 确保所有大小正确 - 在
layoutSubviews
中重新创建图层,删除之前创建的图层
UIBezierPath(arcCenter...
将从 rightSide
开始路径,您也可以使用更简单的变体,如 UIBezierPath(ovalInRect
。考虑到这一点,如果您想在圆 的最顶部开始绘图,您还需要为 M_PI_2 旋转图层
- 你还应该记住,当线宽为 10 时,你的圆路径的一半将被 parentView 的
clipSubviews
覆盖。为防止这种情况,请使用修改后的 parentLayer rect
- 您可能还想提高
lineCap
的可视化效果,购买将其设置为 "round" 样式
如果您不想从动画中获取完成事件,则不需要 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)
结果实际上是这样的:
注:
如果你想为动画层的旋转设置动画,你还应该在动画组中添加额外的动画
我有一个叫 viewProgress
的 UIView
。它是图像中的白色框。我想要一个圆形的进度条,就是图中的绿色圆圈。进度条应该留在白框内,但如您所见,它离得很远。
如何让它留在 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()
基本上你没有什么问题:
- 图层位置不正确 - 框架应等于父视图中父图层的边界
- 你的动画只会播放一次 - 如果你想让它无限播放,请添加类似
animation.repeatCount = MAXFLOAT
的内容
- 确保所有大小正确 - 在
layoutSubviews
中重新创建图层,删除之前创建的图层 UIBezierPath(arcCenter...
将从rightSide
开始路径,您也可以使用更简单的变体,如UIBezierPath(ovalInRect
。考虑到这一点,如果您想在圆 的最顶部开始绘图,您还需要为 M_PI_2 旋转图层
- 你还应该记住,当线宽为 10 时,你的圆路径的一半将被 parentView 的
clipSubviews
覆盖。为防止这种情况,请使用修改后的 parentLayer rect - 您可能还想提高
lineCap
的可视化效果,购买将其设置为 "round" 样式
如果您不想从动画中获取完成事件,则不需要 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)
结果实际上是这样的:
注: 如果你想为动画层的旋转设置动画,你还应该在动画组中添加额外的动画