Анимация StrokeEnd не запускается при установке рамки другого слоя - PullRequest
0 голосов
/ 26 февраля 2019

Проблема: Все анимации работают, когда я не обновляю всю модель.Тем не менее, когда я устанавливаю кадр 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
    }

}
...