设置另一层的帧时,StrokeEnd动画无法开始

时间:2019-02-26 17:44:07

标签: swift core-animation cakeyframeanimation catransaction

问题:当我不更新整个模型时,所有动画均有效。但是,当我在CATransaction.commit之前设置CATextLayer的框架时,CATransaction块中的strokeEnd属性(CAShapelayer.mask)不再具有动画效果。动画从笔画结束开始。最终值几乎没有出现。但是,当我跳过这一行来设置框架时,一切正常,但是模型部分不同步。

我要实现的目标:所有动画的运行和建模均与动画的结束状态保持同步

非工作解决方案:

  • 我试图重新定位动画的代码行
  • 尝试对嵌套的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
    }

}

0 个答案:

没有答案