使用一个CALayer来遮盖另一个CALayer

16

我试图使用CALayers制作甜甜圈形状。一个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;

但是这并没有什么区别。

我还尝试过将Circle的masksToBounds属性设置为YES和NO,但这也没有什么不同。

有什么想法吗?

4个回答

15

正如@David所指出的那样,当前(iOS 5.1)的CALayer掩码是不能被反转的,如果你想使用它们来制作一个简单的圆形CALayer透明孔,这就会造成问题。

要制作一个环状图层可以将圆形CALayer的backgroundColor设为透明,但给它一个borderColor和较宽的borderWidth。以下是dunkin'代码:

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

9
使用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;

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

5
这是掩模图层内容使用的alpha值作为掩模。 (如果将掩模作为子层添加而不是使用它作为掩模,那么当作为掩模使用时,被子层覆盖的所有内容都将可见。当作为掩模使用时,未被子层覆盖的所有内容都将隐藏。)
由于您的小圆是完全透明的,因此所有内容都被掩盖了(被隐藏了)。如果将其backgroundColor设置为任何完全不透明的颜色(只使用alpha值作为掩模),则它将允许这些像素通过。
请注意这与您想要的相反。这将仅留下“甜甜圈洞”的可见部分。没有内置的方法来进行反向遮罩,您需要另外一种方式绘制掩模内容,例如使用CAShapeLayer或使用drawInContext:

1
我使用 CAShapeLayer 作为蒙版,来控制 CALayer 的形状。我使用 UIBezierPath 来指定蒙版 CAShapeLayer 的形状。
我在回答 如何获取 UIBezierPath 的反向路径 中发布了代码。对于甜甜圈形状,请取消注释所注释的行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接