Анимация StrokeEnd не запускается при установке рамки другого слоя
Проблема: все анимации работают, когда я не обновляю всю модель. Тем не менее, когда я устанавливаю кадр CATextLayer перед CATransaction.commit, свойство strokeEnd (CAShapelayer.mask) в блоке CATransaction больше не анимируется. Анимация не запускается, для strokeEnd. Конечное значение появляется немедленно. Однако, когда я пропускаю строку, чтобы установить кадр, все работает нормально, но тогда модель частично не синхронизирована.
Чего я хочу добиться: все анимации работают и моделируются синхронно с конечным состоянием анимации
Нерабочие решения:
- Я попытался изменить положение строк кода анимации.
- Пробовал вложенную CATransaction для анимации штрихов
- Попробовал анимационную группу по строкенду
У вас есть какие-нибудь обходные пути, которые я могу попробовать?
class CircleChartLayer: CALayer {
/// Animated progressArc with gradient filling that shows current value
private let progressArcLayer = CAGradientLayer()
/// Animated knobCircle that shows current value
private let knobCircleLayer = CAShapeLayer()
// Animated label that shows current value
private let labelLayer = CATextLayer()
override init(layer: Any) {
super.init(layer: layer)
setupGradient()
setupLabel()
self.addSublayer(progressArcLayer)
self.addSublayer(knobCircleLayer)
self.addSublayer(labelLayer)
}
override func layoutSublayers() {
setFrames()
}
func animate(to value: Double, withDuration duration: TimeInterval, completion: ((Bool) -> Void)?) {
// if ring.isAnimating {
// ring.pauseAnimation()
// }
/// Current mask of the progressArcLayer
let maskLayer = progressArcLayer.mask as! CAShapeLayer
/// Animation 1 for filling (gradient) of progressArcLayer
let gradientAnimation = animateGradientLayer()
/// Animation 2 for mask/position of progressArcLayer
let shapeAnimation = animateShapeProgressArc()
/// Animation 3 knobCircle at end of progressArcLayer
let knobPositionAnimation = animateKnobPosition()
/// Animation 4 for positioning of layer
let labelPositionAnimation = animateLabelPosition()
/// Sync all animations
CATransaction.begin()
CATransaction.setDisableActions(true)
CATransaction.setAnimationDuration(duration) //duration for both animations
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeInEaseOut))
// Add animations and snyc model
progressArcLayer.add(gradientAnimation, forKey: #keyPath(CAGradientLayer.endPoint))
progressArcLayer.endPoint = stepsEndpoints.last!
progressArcLayer.mask?.add(shapeAnimation, forKey: "strokeEnd")
maskLayer.strokeEnd = CGFloat(value / progressArc.maxValue)
knobCircleLayer.add(knobPositionAnimation, forKey: #keyPath(CAShapeLayer.transform))
progressArc.value = value
updateKnob()
labelLayer.add(labelPositionAnimation, forKey: "path")
/// THE NEXT LINE BREAKS THE "STROKEND" ANIMATION
// When I remove the line all the animations work fine but the sync
// of the labelLayer is missing at the end of the animation
labelLayer.frame = knobCircleLayer.bounds
CATransaction.commit()
}
/// Animates the background of the progressArcLayer
func animateGradientLayer() -> CAKeyframeAnimation {
let animateGradient = CAKeyframeAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
animateGradient.values = endPoints
animateGradient.beginTime = 0
return animateGradient
}
/// Animates the shape of the progressArcLayer
func animateShapeProgressArc() -> CAKeyframeAnimation {
let animateShape = CAKeyframeAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))
animateShape.values = values
animateShape.beginTime = 0
return animateShape
}
/// Animates the knop position which shows the current value
func animateKnobPosition() -> CAKeyframeAnimation {
let animateKnob = CAKeyframeAnimation(keyPath: #keyPath(CAShapeLayer.transform))
animateKnob.values = transformationValues
animateKnob.beginTime = 0
return animateKnob
}
func animateLabelPosition(to radSteps: [CGFloat]) -> CAKeyframeAnimation {
let animateLabel = CAKeyframeAnimation(keyPath: "position")
animateLabel.path = path
animateLabel.beginTime = 0
return animateLabel
}
}