Search code examples
objective-ccocoaquartz-graphicsnsview

NSView / CALayer subtracting mask


I've just wondered about how give negative space to a NSView and and because I can't describe it properly in words I will show you a picture of the desired effect:

http://s16.postimg.org/lci7s2s8l/stackoverflow_problem.jpg

Please don't feel afraid to ask further questions.

Thanks in advance.


Solution

  • One of the options is to setup the following layers' hierarchy:

    CATextLayer
    `-CALayer with desired backgroundColor and CISourceOutCompositing compositingFilter
    

    The corresponding code looks like

    // Setup layer-hosting view.
    NSView *view = [[NSView alloc] initWithFrame:viewFrame];
    view.wantsLayer = YES;
    view.layer = [CALayer layer];
    view.layerUsesCoreImageFilters = YES;
    
    CATextLayer *textLayer = [CATextLayer layer];
    textLayer.string = @"Masked Text";
    textLayer.frame = NSRectToCGRect(viewFrame);
    [view.layer addSublayer:textLayer];
    
    CALayer *colorLayer = [CALayer layer];
    colorLayer.backgroundColor = [[NSColor greenColor] CGColor];
    colorLayer.frame = NSRectToCGRect(viewFrame);
    [textLayer addSublayer:colorLayer];
    
    CIFilter *filter = [CIFilter filterWithName:@"CISourceOutCompositing"];
    [filter setDefaults];
    colorLayer.compositingFilter = filter;
    

    Updated: to have more flexibility with positioning text you can employ the following hierarchy:

    CALayer - this layer should stay empty (let's call it emptyLayer)
    |- CATextLayer
    `- CALayer with CISourceOutCompositing compositingFilter
    

    In this case textLayer can be smaller than emptyLayer and can be positioned the way you want.