CAShapeLayer filling with another CAShapeLayer as

2020-06-28 21:17发布

问题:

My question is about filling animation one CAShapeLayer with another CAShapeLayer. So, I wrote some code that almost achieves my goal.

I created a based layer and fill it with another. Code below:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _shapeLayer = [CAShapeLayer layer];
    [self drawBackgroundLayer];
}
// my main/backgound layer
- (void)drawBackgroundLayer {
    _shapeLayer.frame = CGRectMake(0, 0, 250, 250);
    _shapeLayer.lineWidth = 3;
    _shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    _shapeLayer.fillColor = UIColor.whiteColor.CGColor;
    _shapeLayer.path = [UIBezierPath bezierPathWithRect:_shapeLayer.bounds].CGPath;

    [self.view.layer addSublayer:_shapeLayer];

    [self createCircleLayer];

}

Create a circled mask layer for filling:

- (void)createCircleLayer {

    _shapeLayer.fillColor = UIColor.greenColor.CGColor;

    CAShapeLayer *layer = [CAShapeLayer layer];

    CGFloat radius = _shapeLayer.bounds.size.width*sqrt(2)/2;

    layer.bounds = CGRectMake(0, 0, 2*radius, 2*radius);

    layer.position = CGPointMake(_shapeLayer.bounds.size.width/2, _shapeLayer.bounds.size.height/2);

    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:radius];
    layer.path = path.CGPath;

    layer.transform = CATransform3DMakeScale(0.1, 0.1, 1);
    _shapeLayer.mask = layer;

}

// our result is next]

So, let's animate it. I just transform the layer to fill the whole "_shapeLayer".

- (void)animateMaskLayer:(CAShapeLayer *)maskLayer {

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];

    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1.0)];
    animation.duration = 1;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    [newLayer addAnimation:animation forKey:@"transform"];
}

Now, I want to do the same with this green layer (fill it with red color). But when I use the mask I have red circle and the white background what is obviously. My goal here is to have red circle and green background. Like normal filling with another color. By using inverse mask won't help neither. So, I just have no ideas how to do it.

If you suggest using:

[_shapeLayer addSublayer:layer];

it won't work as there will be not only square but different paths and clipToBounds is not an option.

Thank you for any help!

回答1:

So, the solution is simple. I just use two layers and one mask layer.

First layer: Red layer I want to fill with green layer;

- (void)drawBackgroundLayer {
    _shapeLayer.frame = CGRectMake(20, 20, 250, 250);
    _shapeLayer.lineWidth = 3;
    _shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    _shapeLayer.lineWidth = 3;
    _shapeLayer.fillColor = UIColor.redColor.CGColor;
    _shapeLayer.path = [UIBezierPath bezierPathWithRect:_shapeLayer.bounds].CGPath;

    [self.view.layer addSublayer:_shapeLayer];
    [self drawUpperLayer];
}

Second Layer: Green Layer I use for filling.

- (void)drawUpperLayer {

    _upperLayer = [CAShapeLayer layer];
    _upperLayer.frame = _shapeLayer.frame;
    _upperLayer.lineWidth = 3;
    _upperLayer.strokeColor = [UIColor blackColor].CGColor;
    _upperLayer.fillColor = UIColor.greenColor.CGColor;
    _upperLayer.path = [UIBezierPath bezierPathWithRect:_shapeLayer.bounds].CGPath;

    [_shapeLayer.superlayer addSublayer:_upperLayer];

}

Mask Layer:

- (void)createMaskLayer {

    CAShapeLayer *layer = [CAShapeLayer layer];
    CGFloat radius = _upperLayer.bounds.size.width*sqrt(2)/2;

    layer.bounds = CGRectMake(0, 0, 2*radius, 2*radius);
    layer.fillColor = UIColor.blackColor.CGColor;

    layer.position = CGPointMake(_upperLayer.bounds.size.width/2, _upperLayer.bounds.size.height/2);

    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:radius];
    layer.path = path.CGPath;

    layer.transform = CATransform3DMakeScale(0.1, 0.1, 1);

    _upperLayer.mask = layer;
}

Animate mask layer:

- (void)animateMaskLayer:(CAShapeLayer *)maskLayer {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1.0)];
    animation.duration = 2;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    [maskLayer addAnimation:animation forKey:@"transform"];
}

So, resulted animation: