Search code examples
objective-cioscore-animation

Animate a scale on a circle to keep centerposition


How can I make a circle animate scaling but keep the centerposition of the circle in the same point. This code makes the center of the circle move down and right, seems like its bound in top and left corner by the frame.

This layer is as you can see a mask on another layer.

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, nil, CGRectMake(400, 400, 1000, 1000));

CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
[shapeLayer setPath:path];
[shapeLayer setFrame:[glView frame]];
[shapeLayer setFillColor:[[UIColor blackColor] CGColor]];

[[glView layer] setMask:shapeLayer];

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 0)];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)];
animation.repeatCount = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.duration = 3;
[shapeLayer addAnimation:animation forKey:@"transform.scale"];

Solution

  • A layer is scaled around its anchor point, which by default is the center of the layer's frame. This is explained in Core Animation Programming Guide - Specifying a Layer's Geometry.

    Your problem is that your circle's center is not at the same point as your layer's anchor point.

    So one way to fix your problem is to move shapeLayer.anchorPoint to be the same as the circle's center, like this:

    CGRect circleFrame = CGRectMake(400, 400, 1000, 1000);
    CGPoint circleAnchor = CGPointMake(CGRectGetMidX(circleFrame) / CGRectGetMaxX(circleFrame),
        CGRectGetMidY(circleFrame) / CGRectGetMaxY(circleFrame));
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:circleFrame];
    
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = path.CGPath;
    shapeLayer.anchorPoint = circleAnchor;
    shapeLayer.frame = glView.frame;
    shapeLayer.fillColor = [UIColor blackColor].CGColor;
    
    glView.layer.mask = shapeLayer;
    // and then your animation code
    

    You want to set the anchor point before you set the frame, because setting the anchor point after setting the frame will change the frame.