Вопрос по ios, uiview, calayer, core-animation – Маскировка CALayer с другим CALayer

12

Я пытаюсь сделать пончик с помощью 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;

Но это не имело значения.

Я также пытался установить кругmasksToBounds свойство ДА и НЕТ, но это не имеет значения.

Какие-нибудь мысли?

Ваш Ответ

4   ответа
14

Действительно, @David указывает, что текущие (iOS 5.1) маски CALayer не могут быть обращены, что создает проблему, если вы хотите использовать их, чтобы сделать прозрачную дыру простым круглым CALayer.

То, что вы можете сделать, чтобы получить пончик, это сделать круговой CALayer'sbackgroundColor прозрачный, но дать ему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];
1

Мне удалось сCAShapeLayer маскировкаCALayer, Чтобы указать форму маскировкиCAShapeLayer я использовалUIBezierPath.

Я разместил код в своем ответе на этот вопрос:Как получить обратный путь UIBezierPath, Для формы пончика раскомментируйте закомментированную строку.

5

Это довольно легко, используя 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

Это альфа-значение содержимого маскирующих слоев, которое используется в качестве маски. (Если бы вы добавили маску в качестве подслоя вместо ее использования в качестве маски. Все, что покрыто подслоем, будет видно при использовании в качестве маски. Все, что не покрыто подслой, будет скрыто при использовании в качестве маски .)

Поскольку ваш маленький круг полностью прозрачен, все скрыто (скрыто). Если вы установитеbackgroundColor любого другого, полностью непрозрачного цвета (для маски используется только альфа-значение), тогда он пропустит эти пиксели.

Обратите внимание, что это обратное тому, что вы хотите. В результате у вас останется только «дырка от бублика». видимый. Не существует встроенного способа сделать обратную маску. Вместо этого вы должны нарисовать содержимое маски другим способом, например, используяCAShapeLayer или используяdrawInContext:.

Похожие вопросы