Маска UIView с вырезанным кругом

Ive создал UIView с полупрозрачным черным фоном, чтобы сидеть в моем главном приложении. Цель Im здесь - создать форму вырезанного круга где-то в этом UIView, где не видно полупрозрачный черный фон, дающий эффект черной маски на все изображение, кроме круговой области (это выделите кнопку в этой области).

Мне удалось использовать CAShapeLayer для создания круговой маски, но это имело противоположный эффект (т.е. остальная часть зрения ясна, а внутри круга - полупрозрачный черный). из круга, чтобы сохранить полупрозрачный черный цвет, а затем внутри, чтобы быть ясным. Вот код, который я использовал, как бы я мог заставить его работать в обратном направлении? Мой blackMask - это полупрозрачный черный вид и my buttonCircle - это идентификатор круга, который должен оставаться ясным.

Возможно, мне нужно каким-то образом инвертировать путь?

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = buttonCircle.frame;
CGPathRef path = CGPathCreateWithEllipseInRect(maskRect, NULL);
maskLayer.path = path;
CGPathRelease(path);
blackMask.layer.mask = maskLayer;

EDIT: попробуйте это сейчас, не видя никакой маски вообще с этим:

UIView *circularMaskView = [[UIView alloc] initWithFrame:buttonCircle.frame];
circularMaskView.backgroundColor = [UIColor greenColor];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];

CGPathRef path = CGPathCreateWithEllipseInRect(buttonCircle.frame, NULL);
maskLayer.path = path;
CGPathRelease(path);

circularMaskView.layer.mask = maskLayer;

[blackMask addSubview:circularMaskView];

Ответы

Ответ 1

Итак, вот что я сделал. Я создал собственный подкласс UIView под названием BlackoutView, например:

BlackoutView.h

#import <UIKit/UIKit.h>

@interface BlackoutView : UIView

@property (nonatomic, retain) UIColor *fillColor;
@property (nonatomic, retain) NSArray *framesToCutOut;

@end

BlackoutView.m

#import "BlackoutView.h"

@implementation BlackoutView

- (void)drawRect:(CGRect)rect
{
    [self.fillColor setFill];
    UIRectFill(rect);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(context, kCGBlendModeDestinationOut);

    for (NSValue *value in self.framesToCutOut) {
        CGRect pathRect = [value CGRectValue];
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:pathRect];
        [path fill];
    }

    CGContextSetBlendMode(context, kCGBlendModeNormal);
}

@end

Затем я создаю его как нормальный и задаю свойства цвету маски, которую я хочу использовать, и кадры, которые нужно вырезать из маски:

[blackMask setFillColor:[UIColor colorWithWhite:0.0f alpha:0.8f]];
[blackMask setFramesToCutOut:@[[NSValue valueWithCGRect:buttonCircleA.frame],
                               [NSValue valueWithCGRect:buttonCircleB.frame]]];

Это можно было бы улучшить, разрешив мне вырезать другие фигуры, помимо овалов, но это прекрасно для моих целей здесь и будет легко адаптировано для этого позже. Надеюсь, это поможет другим!

Ответ 2

Если вы используете любое черное изображение для маскирования, то

-(void)maskWithImage:(UIImage*)maskImage toImageView:(UIImageView*)imgView{

    CALayer *aMaskLayer=[CALayer layer];
    aMaskLayer.contents=(id)maskImage.CGImage;

    imgView.layer.mask=aMaskLayer;


}

Если у вас есть пользовательский ShapeLayer для маскировки

-(void)maskWithShapeLayer:(CALayer*)layer toImageView:(UIImageView*)imgView{
    //Layer should be filled with Black color to mask those part of Image
    imgView.layer.mask=layer;
}

Если вы хотите сделать маску ImageView с кругом

-(void)maskWithCircle:(UIImageView*)imgView{

    CAShapeLayer *aCircle=[CAShapeLayer layer];
    aCircle.path=[UIBezierPath bezierPathWithRoundedRect:imgView.bounds cornerRadius:imgView.frame.size.height/2].CGPath; // Considering the ImageView is square in Shape

    aCircle.fillColor=[UIColor blackColor].CGColor;
    imgView.layer.mask=aCircle;

}

Ответ 3

Вот мое преобразование принятого ответа в Swift:

public class OverlayView: UIView {
let fillColor: UIColor = UIColor.grayColor()
public var framesToCutOut: Array<NSValue> = [NSValue]()

override public func drawRect(rect: CGRect) {
    super.drawRect(rect)

    fillColor.setFill()
    UIRectFill(rect)

    if let context: CGContextRef = UIGraphicsGetCurrentContext() {
        CGContextSetBlendMode(context, .DestinationOut)

        for value in framesToCutOut {
            let pathRect: CGRect = value.CGRectValue()
            let path: UIBezierPath = UIBezierPath(ovalInRect: pathRect)
            path.fill()
        }

        CGContextSetBlendMode(context, .Normal)
    }
}