Search code examples
iosobjective-ccashapelayercabasicanimation

How CAShapelayer transform from circle to square (or vice versa) with animation?


How CAShapelayer transform from circle to square (or vice versa) with CABasicAnimation?


Solution

  • After doing some work around, i have ended with this

    enter image description here

    First make global object of UIBezierPath for square and circle path and also for CAShapeLayer object.

    @implementation Demo{
            CAShapeLayer *shapeLayer;
            UIBezierPath *sqPath;
            UIBezierPath *crclePath;
        }
    

    Now, customize your shapeLayer and add to layer like below in viewDidLoad.

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        shapeLayer = [CAShapeLayer layer];
        shapeLayer.strokeColor = [[UIColor redColor] CGColor];
        shapeLayer.lineWidth = 2;
        shapeLayer.lineJoin = kCALineCapRound;
        sqPath = [self makeSquare:self.view.center squareWidth:200];
        shapeLayer.path = [sqPath CGPath];
        crclePath = [self makeCircle:self.view.center radius:100];
        [self.view.layer addSublayer:shapeLayer];
    }
    

    Below is method that will make perfect square

    -(UIBezierPath*)makeSquare:(CGPoint)centrePoint squareWidth:(float)gain{
        float x=centrePoint.x-(gain/2);
        float y=centrePoint.y-(gain/2);
        UIBezierPath *apath = [UIBezierPath bezierPath];
        [apath moveToPoint:CGPointMake(x,y)];
        [apath addLineToPoint:apath.currentPoint];
        [apath addLineToPoint:CGPointMake(x+gain,y)];
        [apath addLineToPoint:apath.currentPoint];
        [apath addLineToPoint:CGPointMake(x+gain,y+gain)];
        [apath addLineToPoint:apath.currentPoint];
        [apath addLineToPoint:CGPointMake(x,y+gain)];
        [apath addLineToPoint:apath.currentPoint];
        [apath closePath];
        return apath;
    }
    

    Below is method helps to make circle

    - (UIBezierPath *)makeCircle:(CGPoint)center radius:(CGFloat)radius
    {
        UIBezierPath *circlePath = [UIBezierPath bezierPath];
        [circlePath addArcWithCenter:center radius:radius startAngle:-M_PI endAngle:-M_PI/2 clockwise:YES];
        [circlePath addArcWithCenter:center radius:radius startAngle:-M_PI/2 endAngle:0 clockwise:YES];
        [circlePath addArcWithCenter:center radius:radius startAngle:0 endAngle:M_PI/2 clockwise:YES];
        [circlePath addArcWithCenter:center radius:radius startAngle:M_PI/2 endAngle:M_PI clockwise:YES];
        [circlePath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:-M_PI clockwise:YES];
        [circlePath closePath];
        return circlePath;
    }
    

    Finally, animation done in action of btnDone which use CABasicAnimation to animate transformation from square to circle or vice versa.

    - (IBAction)btnDone:(id)sender {
        btnDowrk.selected=!btnDowrk.selected;
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
        animation.duration = 1;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        if (btnDowrk.selected) {
            animation.fromValue = (__bridge id)(sqPath.CGPath);
            animation.toValue = (__bridge id)(crclePath.CGPath);
            shapeLayer.path = crclePath.CGPath;
        }
        else{
            animation.fromValue = (__bridge id)(crclePath.CGPath);
            animation.toValue = (__bridge id)(sqPath.CGPath);
            shapeLayer.path = sqPath.CGPath;
        }
        [shapeLayer addAnimation:animation forKey:@"animatePath"];
    }