web-dev-qa-db-ja.com

UIViewを切り抜いた円でマスクします

メインアプリのビュー全体に配置するために、半透明の黒い背景を持つUIViewを作成しました。ここで目指しているのは、そのUIViewのどこかに、半透明の黒い背景が見えないカットアウトの円の形を作成し、円形の領域を除く画像全体に黒いマスクの効果を与えることです(これはその領域のボタンを強調表示します)。

CAShapeLayerを使用して円形マスクを作成できましたが、これは逆の効果があります(つまり、ビューの残りの部分がクリアで、円の内側が半透明の黒です。私が欲しいのは、外側のすべてです。半透明の黒を維持するための円、次に内部を明確にするために使用したコードは次のとおりです。逆の方法で機能させるにはどうすればよいですか?私のblackMaskは半透明の黒のビューで、私のbuttonCircleは明確にしておきたいサークル。

どういうわけか、パスを反転する必要がありますか?

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

編集:今これを試してみて、これでマスクがまったく表示されない:

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

だから、これが私がしたことです。次のように、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]]];

これは、楕円形以外の形状を切り抜くことで改善できる可能性がありますが、ここでの目的には問題がなく、後で簡単に調整できます。うまくいけば、これは他の人を助けます!

18
Luke

黒の画像を使用してマスクしている場合

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

}
8
Mrug

これが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)
    }
}
4
tommys