2012-07-30 20 views
10

私はCALayersでドーナツシェイプを作ろうとしています。 1つのCALayerは大きな円になり、もう1つは中央に位置する小さな円になり、マスクされます。別のCALayerでCALayerをマスキング

大きい円が表示されますが、circle.mask = circleMask;を呼び出すとビューは空に見えます。

ここに私のコードです:

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

私はこのような大きな円のスーパーレイヤのnilを設定しようとしました:

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

しかし、それは違いはありませんでした。

サークルのmasksToBoundsプロパティをYESとNOに設定してみましたが、違いはありませんでした。

どのような考えですか?

答えて

13

実際、@Davidは現在の(iOS 5.1)CALayerマスクを反転することはできません。透明な穴に単純な円形のCALayerを使用する場合は、問題があります。

ドーナツを得るためにできることは、円形のCALayerのbackgroundColorを透明にしますが、それにはborderColorと幅広いborderWidthを付けます。ここではダンキンコードは次のとおりです。

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

これは、マスクとして使用されるマスクレイヤコンテンツのアルファ値です。マスクをマスクとして使用する代わりに、サブレイヤとしてマスクを追加すると、サブレイヤでカバーされているものはすべてマスクとして表示されます。サブレイヤでカバーされていないものは、マスクとして使用すると隠されます。 。)

あなたの小さな円は完全に透明なので、すべてが隠されています。 backgroundColorを完全に不透明な色に設定した場合(アルファ値のみがマスクに使用されます)、それらのピクセルを通過させます。

これはあなたが望むものの逆です。これにより、「ドーナツの穴」だけが見えるようになります。逆のマスクを作成する方法はありません。代わりに、CAShapeLayerを使用するか、drawInContext:を使用するかのように、マスクの内容を他の方法で描画する必要があります。

1

私はCALayerをマスキングCAShapeLayerに成功しました。マスキングの形状を指定するには、UIBezierPathを使用しました。CAShapeLayer

私はこの質問への私の答えにコードを掲載しました:How to Get the reverse path of a UIBezierPath。ドーナツ形状の場合は、コメント行のコメントを外します。

4

これは、UIBezierPathとCAShapeLayerをマスキングレイヤーとして使用するのはかなり簡単です。コードサンプルは、UIViewサブクラスにあるかのように記述されます。

のObjective-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; 

スウィフト:

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