代码之家  ›  专栏  ›  技术社区  ›  TheoK

使用CASpringAnimation设置CAShapeLayer路径的动画

  •  1
  • TheoK  · 技术社区  · 7 年前

    enter image description here

    我有一个习惯 UIView 在这里我添加了一个 CAShapeLayer 作为视图图层的直接子图层:

    private let arcShapeLayer = CAShapeLayer()
    

    这个 现金支付者 awakeFromNib :

    arcShapeLayer.lineWidth = 2.0
    arcShapeLayer.strokeColor = UIColor.black.cgColor
    arcShapeLayer.fillColor = UIColor.lightGray.cgColor
    arcShapeLayer.masksToBounds = false
    layer.masksToBounds = false
    layer.addSublayer(arcShapeLayer)
    

    我宣布这张照片的框架 arcShapeLayer 在 layoutSubviews :

    arcShapeLayer.frame = layer.bounds
    

    然后我有下面的函数,其中我通过了某个百分比(从 ViewController quadCurve 在该层的底部:

    func configureArcPath(curvePercentage: CGFloat) -> CGPath {
    
        let path = UIBezierPath()
        path.move(to: CGPoint.zero)
        path.addLine(to:
            CGPoint(
                x: arcShapeLayer.bounds.minX,
                y: arcShapeLayer.bounds.maxY
            )
        )
    
        path.addQuadCurve(
            to:
            CGPoint(
                x: arcShapeLayer.bounds.maxX,
                y: arcShapeLayer.bounds.maxY
            ),
            controlPoint:
            CGPoint(
                x: arcShapeLayer.bounds.midX,
                y: arcShapeLayer.bounds.maxY + arcShapeLayer.bounds.maxY * (curvePercentage * 0.4)
            )
        )
    
        path.addLine(to:
            CGPoint(
                x: arcShapeLayer.bounds.maxX,
                y: arcShapeLayer.bounds.minY
            )
        )
        path.close()
    
        return path.cgPath
    
    }
    

    然后,我尝试使用弹簧效果为圆弧设置动画,代码如下:

    func animateArcPath() {
    
        let springAnimation = CASpringAnimation(keyPath: "path")
        springAnimation.initialVelocity = 10
        springAnimation.mass = 10
        springAnimation.duration = springAnimation.settlingDuration
        springAnimation.fromValue = arcShapeLayer.path
        springAnimation.toValue = configureArcPath(curvePercentage: 0.0)
        springAnimation.fillMode = .both
        arcShapeLayer.add(springAnimation, forKey: nil)
    
        arcShapeLayer.path = configureArcPath(curvePercentage: 0.0)
    
    }
    

    弧线从不超调 . 尽管弹簧在其原始位置和静止位置之间摆动,但始终无法实现弹簧效果。

    我错过了什么?

    1 回复  |  直到 7 年前
        1
  •  3
  •   matt    7 年前

    我玩弄了这个,我可以报告你是绝对正确的。它与零位夹紧无关。可见动画将在以下位置夹紧: 二者都 极端。

    假设你提供了一个大的质量值,这样超调量应该远远超过凸弓的初始位置 返程 回到起点。然后我们看到的是动画夹钳 二者都 在原来的位置 和 至少要尝试将动画设置为。当弹簧在它们之间摆动时,我们看到动画在一个极端和另一个极端之间发生,但当它达到最大或最小值时,它只是夹在那里,直到它有时间摆动到最大程度并返回。

    path 不喜欢弹跳动画。这一点也在会议上提出 CAShapeLayer path spring animation not 'overshooting'

    enter image description here

    以下是我使用的代码(基于您自己的代码):

    @IBAction func animateArcPath() {
        self.animate(to:-1, in:0.5, from:arcShapeLayer.path!)
    }
    func animate(to arc:CGFloat, in time:Double, from current:CGPath) {
        let goal = configureArcPath(curvePercentage: arc)
        let anim = CABasicAnimation(keyPath: "path")
        anim.duration = time
        anim.fromValue = current
        anim.toValue = goal
        anim.delegate = self
        anim.setValue(arc, forKey: "arc")
        anim.setValue(time, forKey: "time")
        anim.setValue(goal, forKey: "pathh")
        arcShapeLayer.add(anim, forKey: nil)
    }
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if let arc = anim.value(forKey:"arc") as? CGFloat,
            let time = anim.value(forKey:"time") as? Double,
            let p = anim.value(forKey:"pathh") {
            if time < 0.05 {
                return
            }
            self.animate(to:arc*(-0.5), in:time*0.5, from:p as! CGPath)
        }
    }
    
    推荐文章