Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I remove a CAShapeLayer and CABasicAnimation from my UIView?

This is my code:

@objc func drawForm() {
    i = Int(arc4random_uniform(UInt32(formNames.count)))
    var drawPath = actualFormNamesFromFormClass[i]
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.black.cgColor
    shapeLayer.lineWidth = 6
    shapeLayer.frame = CGRect(x: -115, y: 280, width: 350, height: 350)

    var paths: [UIBezierPath] = drawPath()
    let shapeBounds = shapeLayer.bounds
    let mirror = CGAffineTransform(scaleX: 1,
                                   y: -1)
    let translate = CGAffineTransform(translationX: 0,
                                      y: shapeBounds.size.height)
    let concatenated = mirror.concatenating(translate)

    for path in paths {
        path.apply(concatenated)
    }

    guard let path = paths.first else {
        return
    }

    paths.dropFirst()
        .forEach {
            path.append($0)
    }

    shapeLayer.transform = CATransform3DMakeScale(0.6, 0.6, 0)
    shapeLayer.path = path.cgPath

    self.view.layer.addSublayer(shapeLayer)

    strokeEndAnimation.duration = 30.0
    strokeEndAnimation.fromValue = 0.0
    strokeEndAnimation.toValue = 1.0
    shapeLayer.add(strokeEndAnimation, forKey: nil)
}

This code animates the drawing of the shapeLayer path, however I can't find anything online about removing this layer and stopping this basic animation or removing the cgPath that gets drawn... Any help would be greatly appreciated!

like image 394
Thijs van der Heijden Avatar asked Mar 27 '18 17:03

Thijs van der Heijden


2 Answers

You said:

I can't find anything online about removing this layer ...

It is removeFromSuperlayer().

shapeLayer.removeFromSuperlayer()

You go on to say:

... and stopping this basic animation ...

It is removeAllAnimations:

shapeLayer.removeAllAnimations()

Note, this will immediately change the strokeEnd (or whatever property you were animating) back to its previous value. If you want to "freeze" it where you stopped it, you have to grab the presentation layer (which captures the layer's properties as they are mid-animation), save the appropriate property, and then update the property of the layer upon which you are stopping the animation:

if let strokeEnd = shapeLayer.presentation()?.strokeEnd {
    shapeLayer.removeAllAnimations()
    shapeLayer.strokeEnd = strokeEnd
}

Finally, you go on to say:

... or removing the cgPath that gets drawn.

Just set it to nil:

shapeLayer.path = nil

By the way, when you're browsing for the documentation for CAShapeLayer and CABasicAnimation, don't forget to check out the documentation for their superclasses, namely and CALayer and CAAnimation » CAPropertyAnimation, respectively. Bottom line, when digging around looking for documentation on properties or methods for some particular class, you often will have to dig into the superclasses to find the relevant information.

Finally, the Core Animation Programming Guide is good intro and while its examples are in Objective-C, all of the concepts are applicable to Swift.

like image 146
Rob Avatar answered Nov 17 '22 11:11

Rob


You can use an animation delegate CAAnimationDelegate to execute additional logic when an animation starts or ends. For example, you may want to remove a layer from its parent once a fade out animation has completed.

Below code taken from a class that implements CAAnimationDelegate on the layer, when you call The fadeOut function animates the opacity of that layer and, once the animation has completed, animationDidStop(_:finished:) removes it from its superlayer.

extension CALayer : CAAnimationDelegate  {
    func fadeOut() {
        let fadeOutAnimation = CABasicAnimation()
        fadeOutAnimation.keyPath = "opacity"
        fadeOutAnimation.fromValue = 1
        fadeOutAnimation.toValue = 0
        fadeOutAnimation.duration = 0.25
        fadeOutAnimation.delegate = self
        self.add(fadeOutAnimation,
                     forKey: "fade")
    }

    public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        self.removeFromSuperlayer()
    }
}
like image 2
deoKasuhal Avatar answered Nov 17 '22 10:11

deoKasuhal