Masking a CALayer with another CALayer

Eric picture Eric · Jul 30, 2012 · Viewed 19.7k times · Source

I'm trying to make a donut shape with CALayers. One CALayer will be a large circle, the other one will be a smaller circle positioned in its center, masking it.

The large circle displays fine, but whenever I call circle.mask = circleMask; then the view appears empty.

Here's my code:

AriDonut.h

#import <UIKit/UIKit.h>

@interface AriDonut : UIView
-(id)initWithRadius:(float)radius;
@end

AriDonut.m

#import "AriDonut.h"
#import <QuartzCore/QuartzCore.h>

@implementation AriDonut

-(id)initWithRadius:(float)radius{
    self = [super initWithFrame:CGRectMake(0, 0, radius, radius)];
    if(self){

        //LARGE CIRCLE
        CALayer *circle = [CALayer layer];
        circle.bounds = CGRectMake(0, 0, radius, radius);
        circle.backgroundColor = [UIColor redColor].CGColor;
        circle.cornerRadius = radius/2;
        circle.position = CGPointMake(radius/2, radius/2);

        //SMALL CIRLCE
        CALayer *circleMask = [CALayer layer];
        circleMask.bounds = CGRectMake(0, 0, 10, 10);
        circleMask.cornerRadius = radius/2;
        circleMask.position = circle.position;

        //circle.mask = circleMask;

        [self.layer addSublayer:circle];

    }

    return self;
}

I've tried setting the large circle's superlayer nil like this:

CALayer *theSuper = circle.superlayer;
theSuper = nil;

But it didin't make a difference.

I also tried setting Circle's masksToBounds property to YES and NO, but it didn't make a difference.

Any thoughts?

Answer

Eric picture Eric · Jul 31, 2012

Indeed, as @David indicates the current (iOS 5.1) CALayer masks can't be reversed, which poses a problem if you want to use them to make a transparent hole a simple circular CALayer.

What you can do to get a donut is make a circular CALayer's backgroundColor transparent, but give it a borderColor and a wide borderWidth. Here's the dunkin' code:

    CALayer *theDonut = [CALayer layer];
    theDonut.bounds = CGRectMake(0,0, radius, radius);
    theDonut.cornerRadius = radius/2;
    theDonut.backgroundColor = [UIColor clearColor].CGColor;

    theDonut.borderWidth = radius/5;
    theDonut.borderColor = [UIColor orangeColor].CGColor;

    [self.layer addSublayer:theDonut];