2015-05-30 66 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 
}