【问题标题】:Mask a UIView with a cut-out circle用切出的圆圈遮住 UIView
【发布时间】:2014-02-09 13:03:04
【问题描述】:

我创建了一个带有半透明黑色背景的 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];

【问题讨论】:

  • 尝试在按钮后面添加一个额外的视图(同一框架)并将其作为子视图添加到 blackMask
  • 这不行,按钮本身不是一个圆圈。我只想在它周围画一个圆圈。
  • 我的意思是创建一个新视图,将它的背景颜色设置为某个值(非透明)。设置这个新视图的框架与 buttonCircle.frame 相同。将遮罩应用到这个新视图(路径 =buttonCircle.bounds)并将其作为子视图添加到 blackMask。
  • 创建一个反向路径,如this?
  • 这似乎不适用于[UIColor clearColor]。我可以制作一个绿色蒙版或其他颜色、位置等正确的东西,但如果我将颜色设置为清除,它就不起作用了。我在新视图上检查了opaque

标签: ios objective-c uiview core-animation cashapelayer


【解决方案1】:

所以,这就是我所做的。我创建了一个名为BlackoutView 的自定义UIView 子类,如下所示:

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

这可以通过允许我剪掉除椭圆之外的其他形状来改进,但这对我的目的来说很好,以后很容易适应这样做。希望这对其他人有所帮助!

【讨论】:

  • 超级有帮助!你能解释一下为什么在 BlackoutView.m 中设置 fillColor 吗?我没有得到任何透明度,删除前两行为我解决了问题。
  • 还有,drawRect:rect后面需要加CGContextRelease(context);
  • 我尝试了很多解决方案,但这对我很有帮助!非常感谢:)
  • 填充方法出现错误,导致背景颜色为纯黑色。已编辑以解决此问题。
  • 我只是使用标准的backgroundColor 设置了背景颜色,并删除了fillColor 属性和drawRect 中的前两行。设置fillColor 仍然会导致纯黑色。我正在开发 iOS8,但我不确定这与它有什么关系。
【解决方案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;
}

如果你想用 Circle 制作 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)
        }
    }
    

    【讨论】:

    • 如果您用其他 swift 代码调用此 swift 代码,则无需将 CGRects 放入 NSValues -- 只需将 frameToCutOut 设为 [CGRect] 数组
    猜你喜欢
    • 2016-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 2012-01-07
    相关资源
    最近更新 更多