iOS 为圆形视图添加Spinner动画时strokeEnd位置闪烁如何解决
圆形Spinner加载动画闪烁问题修复方案
问题现象
你实现的圆形加载动画效果如下,每轮动画走到3点钟位置时会出现闪烁:
问题原因
闪烁的核心诱因有两个:
CAShapeLayer的strokeStart、strokeEnd属性的合法取值范围为0~1,传入超出范围的值时系统会自动钳制到边界。你初始设置strokeStart的起始值为-0.1,在每轮动画重置的瞬间,strokeStart会被钳制为0,和同时重置为0的strokeEnd相等,描边长度瞬间变为0,产生肉眼可见的闪烁。- 你没有给动画设置
isRemovedOnCompletion = false和fillMode = .forwards,动画每轮结束后会自动跳回layer的model层对应值,和presentation层的展示值不一致也会导致跳闪。
修复代码
直接替换对应方法即可实现流畅无闪烁的加载动画:
func spin() { let circlePathLayer = CAShapeLayer() circlePathLayer.fillColor = nil circlePathLayer.strokeColor = UIColor.red.cgColor circlePathLayer.lineWidth = 6 layer.addSublayer(circlePathLayer) setPath(to: circlePathLayer) animate(layer: circlePathLayer) } private func setPath(to layer: CAShapeLayer) { // 改为从顶部开始的圆形路径,符合常规加载动画的视觉习惯 layer.path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: (bounds.width - layer.lineWidth)/2, startAngle: -CGFloat.pi / 2, endAngle: 3 * CGFloat.pi / 2, clockwise: true).cgPath } private func animate(layer: CAShapeLayer) { // 先给model层赋值,避免动画结束后跳变 layer.strokeStart = 0.9 layer.strokeEnd = 1.0 animateKeyPath(keyPath: "strokeEnd", duration: 1, values: [0.1, 1], layer: layer) animateKeyPath(keyPath: "strokeStart", duration: 1, values: [0, 0.9], layer: layer) // 可选:添加旋转动画,实现更自然的转圈效果 let rotateAnim = CABasicAnimation(keyPath: "transform.rotation") rotateAnim.fromValue = 0 rotateAnim.toValue = CGFloat.pi * 2 rotateAnim.duration = 2 rotateAnim.repeatCount = .infinity layer.add(rotateAnim, forKey: "rotate") } private func animateKeyPath(keyPath: String, duration: CFTimeInterval, values: [CGFloat], layer: CAShapeLayer) { let animation = CAKeyframeAnimation(keyPath: keyPath) animation.values = values animation.calculationMode = .linear animation.duration = duration animation.repeatCount = .infinity // 新增动画配置,避免自动移除和跳变 animation.isRemovedOnCompletion = false animation.fillMode = .forwards layer.add(animation, forKey: animation.keyPath) }
内容的提问来源于stack exchange,提问作者iOS
相关产品推荐
相关产品推荐

