Jagveer Singh
Jagveer Singh

Reputation: 2328

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

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

Upvotes: 0

Views: 1548

Answers (3)

ajay_nasa
ajay_nasa

Reputation: 2298

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"];
}

Upvotes: 4

Pooja Srivastava
Pooja Srivastava

Reputation: 721

Here is create the circle path:

- (UIBezierPath *)circlePathWithCenter:(CGPoint)center radius:(CGFloat)radius
{    
UIBezierPath *circlePath = [UIBezierPath bezierPath];
[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:3*M_PI/2 clockwise:YES];
[circlePath addArcWithCenter:center radius:radius startAngle:3*M_PI/2 endAngle:M_PI clockwise:YES];
[circlePath closePath];
return circlePath;
}

Here is the square path:

- (UIBezierPath *)squarePathWithCenter:(CGPoint)center size:(CGFloat)size
{
CGFloat startX = center.x-size/2;
CGFloat startY = center.y-size/2;

UIBezierPath *squarePath = [UIBezierPath bezierPath];
[squarePath moveToPoint:CGPointMake(startX, startY)];
[squarePath addLineToPoint:CGPointMake(startX+size, startY)];
[squarePath addLineToPoint:CGPointMake(startX+size, startY+size)];
[squarePath addLineToPoint:CGPointMake(startX, startY+size)];
[squarePath closePath];
return squarePath;
}

The animation Part

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.duration = 1;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

animation.fromValue = (__bridge id)(self.stateLayer.path);
    animation.toValue = (__bridge id)(self.stopPath.CGPath);
self.stateLayer.path = self.stopPath.CGPath;

[self.stateLayer addAnimation:animation forKey:@"animatePath"];

Upvotes: 1

Ketan Parmar
Ketan Parmar

Reputation: 27438

You can play with cornerRadius. For example,

   UIView *testView = [[UIView alloc]initWithFrame:CGRectMake(50, 50, 50, 50)];

CAShapeLayer *layer = [[CAShapeLayer alloc]initWithLayer:testView.layer];  // this is square layer

layer.cornerRadius = 25.0; // this is round layer

layer.cornerRadius = 0.0; // this is again square layer

You can switch views directly from round to square and square to round like above approach!

Upvotes: 1

Related Questions