CABasicAnimation修改CAShapeLayer颜色后未停在toValue反而重置问题求助
问题根源
- Core Animation的动画默认仅作用于呈现层(presentation layer,负责显示动画过程的临时层),不会修改*模型层(model layer,存储layer实际属性值的层)*的原始属性。动画执行完成后会自动从layer上移除,界面会自动恢复到模型层存储的原始属性状态,这就是动画结束后回弹的原因。
- 使用animationDidStop代理设置属性时,动画已经先完成移除逻辑,界面会先闪一下原始属性对应的效果,再更新到你手动设置的目标值,因此会出现闪烁。
正确解决方案
推荐优先使用方案1,无后续逻辑隐患。
方案1:提前更新模型层属性 + 显式指定动画起始值
在添加动画前直接将layer的对应属性设置为目标终值,同时给动画指定fromValue为动画开始前的原始值,动画结束后模型层本身已经是终值,就算动画被移除也不会出现回弹或闪烁。
修改后的animateLayerOnTap代码如下:
func animateLayerOnTap() { // 先保存动画开始前的原始值 let originStrokeColor = layer.strokeColor let originFillColor = layer.fillColor // 提前将模型层属性设置为目标终值 // 注意:你原代码中strokeAnim的toValue和初始strokeColor一致,不会有动画效果,这里我示例改为蓝色,你可以按需修改 layer.strokeColor = UIColor.blue.cgColor layer.fillColor = UIColor.lightGray.cgColor let strokeAnim = CABasicAnimation(keyPath: "strokeColor") strokeAnim.fromValue = originStrokeColor strokeAnim.toValue = UIColor.blue.cgColor strokeAnim.duration = 0.8 strokeAnim.repeatCount = 0 strokeAnim.autoreverses = false let fillAnim = CABasicAnimation(keyPath: "fillColor") fillAnim.fromValue = originFillColor fillAnim.toValue = UIColor.lightGray.cgColor fillAnim.duration = 0.8 fillAnim.repeatCount = 0 fillAnim.autoreverses = false layer.add(fillAnim, forKey: "fillColor") layer.add(strokeAnim, forKey: "strokeColor") }
方案2:配置动画停留参数(不推荐,仅适用于临时动画场景)
给动画设置fillMode和isRemovedOnCompletion属性,让动画结束后停留在终值且不被移除。缺点是模型层的属性还是原始值,后续对该layer做其他操作时容易出现属性不匹配的问题。
代码示例:
func animateLayerOnTap() { let strokeAnim = CABasicAnimation(keyPath: "strokeColor") // 同样注意修改为你需要的目标描边色 strokeAnim.toValue = UIColor.blue.cgColor strokeAnim.duration = 0.8 strokeAnim.repeatCount = 0 strokeAnim.autoreverses = false // 新增以下两行配置 strokeAnim.fillMode = .forwards strokeAnim.isRemovedOnCompletion = false let fillAnim = CABasicAnimation(keyPath: "fillColor") fillAnim.toValue = UIColor.lightGray.cgColor fillAnim.duration = 0.8 fillAnim.repeatCount = 0 fillAnim.autoreverses = false // 新增以下两行配置 fillAnim.fillMode = .forwards fillAnim.isRemovedOnCompletion = false layer.add(fillAnim, forKey: "fillColor") layer.add(strokeAnim, forKey: "strokeColor") }
额外注意点
你原代码中strokeAnim.toValue设置为UIColor.red.cgColor,和你创建layer时设置的初始strokeColor完全一致,这个动画本身不会产生任何视觉变化,如果你需要修改描边颜色,记得把这个值替换为你要的目标色值。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

