2015-05-30 39 views
0

我正在开发一个应用程序,其中包含许多正在移动的自定义NSView对象。我实现了一个高斯模糊的背景过滤器自定义的NSView子类,像这样的一个:带遮罩的CIFilter for OS X的NSView应用程序

- (id)init { 
    self = [super init]; 
    if (self) { 

     ... 

     CIFilter *saturationFilter = [CIFilter filterWithName:@"CIColorControls"]; 
     [saturationFilter setDefaults]; 
     [saturationFilter setValue:@.5 forKey:@"inputSaturation"]; 

     CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; 
     [blurFilter setDefaults]; 
     [blurFilter setValue:@2.0 forKey:@"inputRadius"]; 

     self.wantsLayer = YES; 
     self.layer.backgroundColor = [NSColor clearColor].CGColor; 
     self.layer.masksToBounds = YES; 
     self.layer.needsDisplayOnBoundsChange = YES; 
     self.layerUsesCoreImageFilters = YES; 

     [self updateFrame]; //this is where the frame size is set 

     self.layer.backgroundFilters = @[saturationFilter, blurFilter]; 

     ... 

     return self; 
    } 
    else return nil; 
} 

这个伟大的工程,并创建视图的整个内容中的高斯模糊效果。问题是我不希望高斯模糊覆盖整个视图。有关于一个NSView的实际大小和它的内容框的图纸之间的(故意)12像素填充:

- (void)drawRect:(NSRect)dirtyRect { 
    [super drawRect:dirtyRect]; 

    NSColor* strokeColor = [NSColor colorWithRed:.5 green:.8 blue:1 alpha:1]; 
    NSColor* fillColor = [NSColor colorWithRed:.5 green:.8 blue:1 alpha:.2]; 

    ... 

    [strokeColor setStroke]; 
    [fillColor setFill]; 
    NSBezierPath *box = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(self.bounds.origin.x + 12, self.bounds.origin.y + 12, self.bounds.size.width - 24, self.bounds.size.height - 24) xRadius:6 yRadius:6]; 
    box.lineWidth = 6; 
    [box stroke]; 
    [box fill]; 

    ... 
} 

这样做的原因填充的是有GUI的一些作品居住在这个区域和被无缝地绘制在包含框中。我想掩盖模糊效果只对绘制的盒子的内部产生影响,而不是对整个视图产生影响。这是我尝试过的。

ATTEMPT 1:创建一个子层

我创建在一个的NSView子层与适当大小的帧,并增加模糊效果这一子层。问题:模糊效果似乎只适用于直接父层,所以不模糊NSView后面的内容,它模糊了NSView的self.layer(基本上是空的)的内容。

ATTEMPT 2:创建掩蔽层

我试图创建一个掩模层,并将其设置到self.layer.mask。但是,由于GUI内容的位置确实发生了变化(通过DrawRect函数),我需要获取当前图层的副本作为遮罩层。我尝试了下面的代码,但它没有效果。

self.layer.mask = nil; 
NSArray *bgFilters = self.layer.backgroundFilters; 
self.layer.backgroundFilters = nil; 
CALayer *maskingLayer = self.layer.presentationLayer; 
self.layer.mask = maskingLayer; 
self.layer.backgroundFilters = bgFilters; 

未遂3:画一个屏蔽层直接

我找不到如何直接绘制一个图层上的任何实例。我无法使用静态UIImage来进行测试,因为正如我上面所说的,面具必须随用户交互而改变。我正在寻找与DrawRect函数等价的东西。任何帮助,将不胜感激。

SO ...

在我看来,该子层的方法是去最好的和最简单的方式,如果我可以弄清楚如何改变的模糊效果的优先级为后面的背景NSView不是NSView背景层的子层。

回答

0

那么,我仍然想知道是否有更优雅的方式,但我找到了一个可行的解决方案。基本上,我已经从修改过的drawRect函数绘制的NSImage创建了一个遮罩层:

- (id)init { 
    self = [super init]; 
    if (self) { 

     // SETUP VIEW SAME AS ABOVE 

     CALayer *maskLayer = [CALayer layer]; 
     maskLayer.contents = [NSImage imageWithSize:self.frame.size flipped:YES drawingHandler:^BOOL(NSRect dstRect) { 
      [self drawMask:self.bounds]; 
      return YES; 
     }]; 
     maskLayer.frame = self.bounds; 
     self.layer.mask = maskLayer; 

     return self; 
    } 
    else return nil; 
} 


- (void)drawMask:(NSRect)dirtyRect { 
    [[NSColor clearColor] set]; 
NSRectFill(self.bounds); 
    [[NSColor blackColor] set]; 

    // SAME DRAWING CODE AS drawRect 
    // EXCEPT EVERYTHING IS SOLID BLACK (NO ALPHA TRANSPARENCY) 
    // AND ONLY NEED TO DRAW PARTS THAT EFFECT THE EXTERNAL BOUNDARIES 
}