2012-07-30 13 views
10

Próbuję nadać kształt pączków z CALayers. Jedna CALayer będzie dużym kołem, druga będzie mniejszym kołem umieszczonym w jego środku, maskującym.Maskowanie CALayera za pomocą innego CALayera

Duże kółko wyświetla się dobrze, ale gdy dzwonię pod numer circle.mask = circleMask;, widok jest pusty.

Oto mój kod:

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; 
} 

Próbowałem ustawienie dużego okręgu superlayer nil tak:

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

Ale to nie miało znaczenia.

Próbowałem również ustawić właściwość Circle na masksToBounds na TAK i NIE, ale to nie miało znaczenia.

Jakieś myśli?

Odpowiedz

13

Rzeczywiście, ponieważ @David wskazuje bieżący (iOS 5.1), maski CALayer nie mogą być odwrócone, co stanowi problem, jeśli chcesz użyć ich do utworzenia przezroczystego otworu w prostym okrągłym CALayerze.

Co można zrobić, aby dostać pączka to zrobić okrągły CALayer na backgroundColor przejrzyste, ale dać mu borderColor oraz szeroki borderWidth. Oto Dunkin' Kod:

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]; 
4

Jest to wartość alpha zawartości warstw maskowania, która jest używana jako maska. (Jeśli dodasz maskę jako podwarstwę zamiast używać jej jako maski, wszystko, co jest objęte podwarstwą, będzie widoczne, gdy zostanie użyte jako maska. Wszystko, co nie jest objęte podwarstwą, będzie ukryte, gdy zostanie użyte jako maska .)

Ponieważ twoje małe kółko jest całkowicie przezroczyste, wszystko jest zamaskowane (jest ukryte). Jeśli ustawisz jego backgroundColor na dowolny, całkowicie nieprzezroczysty kolor (do maski zostanie użyta tylko wartość alfa), wówczas przepuścisz te piksele.

Należy zauważyć, że jest to przeciwieństwo tego, co chcesz. Dzięki temu zobaczysz tylko "dziurę pączka". Nie ma wbudowanego sposobu na wykonanie maski odwrotnej Zamiast tego należałoby narysować zawartość maski w inny sposób, np. Używając CAShapeLayer lub używając drawInContext:.

1

udało mi się z CAShapeLayer maskowania CALayer. Aby określić kształt maski CAShapeLayer użyłem UIBezierPath.

Napisałem kod w mojej odpowiedzi na to pytanie: How to Get the reverse path of a UIBezierPath. Dla kształtu pączka odkomentuj skomentowaną linię.

4

Jest to całkiem proste przy użyciu UIBezierPath i warstwy CAShapeLayer jako warstwy maskującej. Przykład kodu napisany tak, jakby był w podklasie UIView.

Cel C:

CGRect outerRect = self.bounds; 
CGFloat inset = 0.2 * outerRect.size.width; // adjust as necessary for more or less meaty donuts 
CGFloat innerDiameter = outerRect.size.width - 2.0 * inset; 
CGRect innerRect = CGRectMake(inset, inset, innerDiameter, innerDiameter); 
UIBezierPath *outerCircle = [UIBezierPath bezierPathWithRoundedRect:outerRect cornerRadius:outerRect.size.width * 0.5]; 
UIBezierPath *innerCircle = [UIBezierPath bezierPathWithRoundedRect:innerRect cornerRadius:innerRect.size.width * 0.5]; 
[outerCircle appendPath:innerCircle]; 
CAShapeLayer *maskLayer = [CAShapeLayer new]; 
maskLayer.fillRule = kCAFillRuleEvenOdd; // Going from the outside of the layer, each time a path is crossed, add one. Each time the count is odd, we are "inside" the path. 
maskLayer.path = outerCircle.CGPath; 
self.layer.mask = maskLayer; 

Swift:

let outerRect = self.bounds 
let inset: CGFloat = 0.2 * outerRect.width // adjust as necessary for more or less meaty donuts 
let innerDiameter = outerRect.width - 2.0 * inset 
let innerRect = CGRect(x: inset, y: inset, width: innerDiameter, height: innerDiameter) 
let outerCircle = UIBezierPath(roundedRect: outerRect, cornerRadius: outerRect.width * 0.5) 
let innerCircle = UIBezierPath(roundedRect: innerRect, cornerRadius: innerRect.width * 0.5) 
outerCircle.appendPath(innerCircle) 
let mask = CAShapeLayer() 
mask.fillRule = kCAFillRuleEvenOdd 
mask.path = outerCircle.CGPath 
self.layer.mask = mask 
Powiązane problemy