1
votes

TL;DR: Basically, my problem is the same as this question.

I followed the excellent answer (as always) by Rob Mayoff. My problem is that I am not using a CAGradientLayer but a CAShapeLayer and it does not work.

I use a CAShapeLayer instead of a UIBezierPath because I need to animate the path colour and shadow.

Though, the problem regards the shape of the path when the device rotates: the animation of CAShapeLayer looks awful, in fact, it does not even animate, It just immediately arrange the path to the new bounds.

I used to add the CAShapeLayer as a sublayer, but reading some answers here I tried to subclass UIView and set its layer to CAShapeLayer so that the view would manage the rotation animation automagically, but the result is the same.

If I draw using UIBezierPath it does work perfectly (but I need CAShapeLayer features, unfortunately)

Here is my code:

import UIKit

class CaShapeLayerView: UIView {
    
    override class func layerClass () -> AnyClass{
        return CAShapeLayer.self
    }
    
    override func drawRect(rect: CGRect) {
        
        var bezierPath = UIBezierPath()
        
        // create a random scribble :)
        bezierPath.moveToPoint(CGPoint(x: 0, y: 0))
        bezierPath.addCurveToPoint(CGPoint(x:self.bounds.width, y:self.bounds.height), controlPoint1: CGPoint(x: self.bounds.width/50, y: self.bounds.height/2), controlPoint2: CGPoint(x: self.bounds.width/40, y: self.bounds.height/8*10))
        
        // draw UIBezierPath
        UIColor.redColor().set()
        bezierPath.lineWidth = 20
        bezierPath.stroke()
        
        // draw CAShapeLayer
        var shapeLayer = self.layer as CAShapeLayer

        shapeLayer.strokeColor = UIColor.blueColor().CGColor
        shapeLayer.fillColor = nil
        shapeLayer.lineWidth = 16      
        shapeLayer.path = bezierPath.CGPath
        
    }
}
 

Rotating the device you will see the difference between the UIBezierPath in red and the CAShapeLayer in blue. I assure the with my actual path the "animation" with CAShapeLayer is awful.

Am I missing something?

Thank you very much everybody.

1
can you share your animation code?Vitalii Gozhenko
Hi @VitaliyGozhenko there is no animation code:) I mean the animation done automatically by a view when the device is rotated. I am gonna add a link to a similar question so that you will understandJ.Williams
@J.Williams : Did you managed to find a solution to ur problem? On device rotation, I found out that a custom view having CAShapeLayer as root layer, did not solve the problem of view resize on changing device orientation.Wael Showair

1 Answers

1
votes

This code at your drawRect isn't animatable:

        UIColor.redColor().set()
        bezierPath.lineWidth = 20
        bezierPath.stroke()

That's why your image partially redraw on device rotation

You need something like this:

class CAShapeLayerView: UIView {
    var firstShapeLayer, secondShapeLayer:CAShapeLayer
    required init(coder aDecoder: NSCoder) {
        firstShapeLayer = CAShapeLayer()
        secondShapeLayer = CAShapeLayer()
        super.init(coder: aDecoder)
    }

    override class func layerClass () -> AnyClass{
        return CAShapeLayer.self
    }

    override func awakeFromNib() {
        self.firstShapeLayer.lineWidth = 20
        self.firstShapeLayer.strokeColor = UIColor.redColor().CGColor
        self.firstShapeLayer.fillColor = nil

        self.secondShapeLayer.strokeColor = UIColor.blueColor().CGColor
        self.secondShapeLayer.fillColor = nil
        self.secondShapeLayer.lineWidth = 16
        self.layer.addSublayer(self.firstShapeLayer)
        self.layer.addSublayer(self.secondShapeLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews();
        var bezierPath = UIBezierPath()

        // create a random scribble :)
        bezierPath.moveToPoint(CGPoint(x: 0, y: 0))
        bezierPath.addCurveToPoint(CGPoint(x:self.bounds.width, y:self.bounds.height), controlPoint1: CGPoint(x: self.bounds.width/50, y: self.bounds.height/2), controlPoint2: CGPoint(x: self.bounds.width/40, y: self.bounds.height/8*10))

        self.firstShapeLayer.path = bezierPath.CGPath
        self.secondShapeLayer.path = bezierPath.CGPath
    }

}