CAAnimationGroup嵌套两个CABasicAnimation的动画异常问题
问题描述
想要实现标签栏的线条动画效果,当前代码已接近预期,但动画组完成后,两个指定点之间会保留一条实线,而非在第二个动画结束后结束图层状态。
当前代码如下:
let start = fromTab.convert(fromLineView.center, to: backgroundView) let end = toTab.convert(toLineView.center, to: backgroundView) let path = UIBezierPath() path.move(to: start) path.addLine(to: end) let shapeLayer = CAShapeLayer() shapeLayer.path = path.cgPath shapeLayer.strokeColor = ColorConstants.green.cgColor shapeLayer.lineWidth = 4 shapeLayer.lineCap = .round backgroundView.layer.addSublayer(shapeLayer) let startAnimation = CABasicAnimation(keyPath: "strokeEnd") startAnimation.duration = 1 startAnimation.fromValue = 0 startAnimation.toValue = 1 let endAnimation = CABasicAnimation(keyPath: "strokeStart") endAnimation.beginTime = startAnimation.duration endAnimation.duration = 1 endAnimation.fromValue = 0 endAnimation.toValue = 1 let animation = CAAnimationGroup() animation.animations = [startAnimation, endAnimation] animation.duration = startAnimation.duration + endAnimation.duration shapeLayer.add(animation, forKey: "lineAnimation")
当前效果:动画结束后两点间仍保留实线,不符合预期。
解决方案
问题核心在于Core Animation默认仅驱动视觉动画,不会修改图层的真实属性,动画结束后图层会自动回到初始状态(strokeStart=0、strokeEnd=1),因此会显示完整线条。可通过以下步骤修复:
设置图层初始状态为动画结束后的状态
在添加动画前,将shapeLayer的strokeStart和strokeEnd都设为1,确保动画结束后图层保持无线条的状态。调整动画的状态过渡逻辑
保持原有动画的fromValue和toValue逻辑,同时通过fillMode和removedOnCompletion确保动画过程中状态正确过渡。可选:动画结束后移除图层
若希望线条完全消失后移除图层,可添加动画完成回调,手动移除shapeLayer。
修改后的完整代码:
let start = fromTab.convert(fromLineView.center, to: backgroundView) let end = toTab.convert(toLineView.center, to: backgroundView) let path = UIBezierPath() path.move(to: start) path.addLine(to: end) let shapeLayer = CAShapeLayer() shapeLayer.path = path.cgPath shapeLayer.strokeColor = ColorConstants.green.cgColor shapeLayer.lineWidth = 4 shapeLayer.lineCap = .round // 设置图层初始状态为动画结束后的无线条状态 shapeLayer.strokeStart = 1 shapeLayer.strokeEnd = 1 backgroundView.layer.addSublayer(shapeLayer) let startAnimation = CABasicAnimation(keyPath: "strokeEnd") startAnimation.duration = 1 startAnimation.fromValue = 0 startAnimation.toValue = 1 startAnimation.fillMode = .forwards startAnimation.removedOnCompletion = false let endAnimation = CABasicAnimation(keyPath: "strokeStart") endAnimation.beginTime = startAnimation.duration endAnimation.duration = 1 endAnimation.fromValue = 0 endAnimation.toValue = 1 endAnimation.fillMode = .forwards endAnimation.removedOnCompletion = false let animation = CAAnimationGroup() animation.animations = [startAnimation, endAnimation] animation.duration = startAnimation.duration + endAnimation.duration animation.fillMode = .forwards animation.removedOnCompletion = false // 可选:动画完成后移除线条图层 CATransaction.setCompletionBlock { shapeLayer.removeFromSuperlayer() } shapeLayer.add(animation, forKey: "lineAnimation") CATransaction.commit()
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

