16

I'm trying to make a donut shape with CALayers. One CALayer will be a large circle, the other one will be a smaller circle positioned in its center, masking it.

The large circle displays fine, but whenever I call circle.mask = circleMask; then the view appears empty.

Here's my code:

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

I've tried setting the large circle's superlayer nil like this:

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

But it didin't make a difference.

I also tried setting Circle's masksToBounds property to YES and NO, but it didn't make a difference.

Any thoughts?

4

4 回答 4

15

实际上,正如@David 指出的当前(iOS 5.1)CALayer 蒙版无法反转,如果您想使用它们将透明孔制作成简单的圆形 CALayer,这会带来问题。

获得甜甜圈的方法是使圆形 CALayerbackgroundColor透明,但给它 aborderColor和 wide 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];
于 2012-07-31T15:44:58.470 回答
9

使用 UIBezierPath 和 CAShapeLayer 作为遮罩层非常容易。就像在 UIView 子类中一样编写的代码示例。

目标-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
于 2015-12-06T03:56:41.720 回答
5

它是用作遮罩的遮罩层内容的 alpha 值。(如果您将蒙版添加为子图层而不是将其用作蒙版。当用作蒙版时,子图层覆盖的所有内容都将可见。当用作蒙版时,子图层未覆盖的所有内容都将隐藏.)

由于你的小圆圈是完全透明的,所以一切都被掩盖了(被隐藏了)。如果将backgroundColor其设置为任何完全不透明的颜色(仅 alpha 值用于遮罩),那么它将让这些像素通过。

请注意,这与您想要的相反。这将使您只看到“甜甜圈的洞”。没有内置的方法来做一个反向掩码相反,你必须以其他方式绘制掩码的内容,比如使用 aCAShapeLayer或 using drawInContext:

于 2012-07-30T11:21:20.053 回答
1

我成功CAShapeLayer屏蔽了一个CALayer. CAShapeLayer要指定我使用的遮罩的形状UIBezierPath

我在对这个问题的回答中发布了代码:如何获取 UIBezierPath 的反向路径。对于甜甜圈形状,取消注释注释行。

于 2013-03-08T14:25:50.443 回答