2012-03-14 83 views
39

想要创建一个内部有一个透明框架的视图,以便透过这个透明框架可以看到视图背后的视图,但是在这之外的区域不会透视。所以基本上是视图中的一个窗口。在UIView中切透明洞

希望能够做这样的事情:

CGRect hole = CGRectMake(100, 100, 250, 250); 
CGContextRef context = UIGraphicsGetCurrentContext(); 

CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 
CGContextFillRect(context, rect); 

CGContextAddRect(context, hole); 
CGContextClip(context); 

CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); 
CGContextFillRect(context, rect); 

但明确不会覆盖黑色,所以整个背景是黑色的。任何想法沿着这些线?

+0

2017年死简易的解决方案http:// stackoverflow。com/q/42330283/294884 – Fattie 2017-02-19 18:15:27

回答

-3

这样做是相反的!将您希望通过“洞”看到的视图放在适当尺寸的单独视图中。然后将“clipsToBounds”设置为YES并将该视图置于顶部。那个带有“透明”框架的视图就是最底层的视图。 “clipsToBounds”意味着盒子/孔外的所有东西都被切断。然后你可能不得不处理如何处理触摸。但那是另一个问题。也许在相应的视图上设置userInteractionEnabled就足够了。

+0

这样做太复杂,无法正确执行,窗口可能随滚动或任何其他动画移动,而“后面”视图一定不能移动,不是吗?但是,您的解决方案是一个很好的观点,感谢分享。 – 2012-03-14 22:56:25

+0

这并不复杂。你需要得到视图的层次结构:)什么东西应该移动如何以及应该修复什么? – Carsten 2012-03-14 23:08:47

+0

我不知道,这不是我的问题你知道:)但任何类型的动画是可能的,我不可能错误地说超过一半的观点可以在iOs世界滚动。这给了我们'窗口'的移动,我希望'前景'不要一起移动。 – 2012-03-14 23:16:46

0

好吧,我将不得不回答评论,并填写答案表格:) 我真的很喜欢Carsten提供更多关于他建议的最佳方式的信息。

你可以使用

+ (UIColor *)colorWithPatternImage:(UIImage *)image 

创建任何复杂的背景“色”的形象。如果您熟悉绘图类,则可以以编程方式创建图像,或者如果预定义了窗框,则可以静态创建图像。

0

端上“打假”,它

窗框是一个属性

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); 
CGContextFillRect(context, rect); 
CGRect rootFrame = [[Navigation rootController] view].frame; 

CGSize deviceSize = CGSizeMake(rootFrame.size.width, rootFrame.size.height); 

CGRect topRect = CGRectMake(0, 0, deviceSize.width, windowFrame.origin.y); 
CGRect leftRect = CGRectMake(0, topRect.size.height, windowFrame.origin.x, windowFrame.size.height); 
CGRect rightRect = CGRectMake(windowFrame.size.width+windowFrame.origin.x, topRect.size.height, deviceSize.width-windowFrame.size.width+windowFrame.origin.x, windowFrame.size.height); 
CGRect bottomRect = CGRectMake(0, windowFrame.origin.y+windowFrame.size.height, deviceSize.width, deviceSize.height-windowFrame.origin.y+windowFrame.size.height); 

CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 
CGContextFillRect(context, topRect); 
CGContextFillRect(context, leftRect); 
CGContextFillRect(context, rightRect); 
CGContextFillRect(context, bottomRect); 
5

这将做剪辑:

CGContextRef context = UIGraphicsGetCurrentContext(); 

CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor); 
CGContextFillRect(context, rect); 

CGRect holeRectIntersection = CGRectIntersection(CGRectMake(50, 50, 50, 50), rect); 

if(CGRectIntersectsRect(holeRectIntersection, rect)) 
{ 
    CGContextAddEllipseInRect(context, holeRectIntersection); 
    CGContextClip(context); 
    CGContextClearRect(context, holeRectIntersection); 
    CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); 
    CGContextFillRect(context, holeRectIntersection); 
} 
40

这是我实现(像我一样需要有一个观点透明部分):

标头(.h)文件:

// Subclasses UIview to draw transparent rects inside the view 

#import <UIKit/UIKit.h> 

@interface PartialTransparentView : UIView { 
    NSArray *rectsArray; 
    UIColor *backgroundColor; 
} 

- (id)initWithFrame:(CGRect)frame backgroundColor:(UIColor*)color andTransparentRects:(NSArray*)rects; 

@end 

实施(.M)文件:

#import "PartialTransparentView.h" 
#import <QuartzCore/QuartzCore.h> 

@implementation PartialTransparentView 

- (id)initWithFrame:(CGRect)frame backgroundColor:(UIColor*)color andTransparentRects:(NSArray*)rects 
{ 
    backgroundColor = color; 
    rectsArray = rects; 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 
     self.opaque = NO; 
    } 
    return self; 
} 

// Only override drawRect: if you perform custom drawing. 
// An empty implementation adversely affects performance during animation. 
- (void)drawRect:(CGRect)rect 
{ 
    // Drawing code 
    [backgroundColor setFill]; 
    UIRectFill(rect); 

    // clear the background in the given rectangles 
    for (NSValue *holeRectValue in rectsArray) { 
     CGRect holeRect = [holeRectValue CGRectValue]; 
     CGRect holeRectIntersection = CGRectIntersection(holeRect, rect); 
     [[UIColor clearColor] setFill]; 
     UIRectFill(holeRectIntersection); 
    } 

} 


@end 

我们添加视图与部分透明,你需要导入PartialTransparentView定制UIView子类,然后用它如下:

NSArray *transparentRects = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:CGRectMake(0, 50, 100, 20)],[NSValue valueWithCGRect:CGRectMake(0, 150, 10, 20)], nil]; 
PartialTransparentView *transparentView = [[PartialTransparentView alloc] initWithFrame:CGRectMake(0,0,200,400) backgroundColor:[UIColor colorWithWhite:1 alpha:0.75] andTransparentRects:rects]; 
[self.view addSubview:backgroundView]; 

这将创建2个透明rects的图。 当然,您可以根据需要添加尽可能多的矩形,或者只使用一个。 上面的代码只处理矩形,所以如果你想使用圆形,你将不得不修改它。

+0

对于CIRCULAR透明层,修改绘制矩形为: – 2014-07-26 09:55:57

+0

嘿@MosibAsad,你能让我们知道修改绘制矩形为什么吗?它没有出现..谢谢! – daspianist 2014-11-25 20:39:19

+0

嘿Daspianist,请在下一条评论中查看我的完整答案。这么晚才回复很抱歉!! – 2015-02-23 06:47:37

18

Lefteris答案是绝对正确的,但是,它会创建透明Rects。对于圆形透明层,修改绘制矩形作为

- (void)drawRect:(CGRect)rect { 

    [backgroundColor setFill]; 
    UIRectFill(rect); 

    for (NSValue *holeRectValue in rectsArray) { 
     CGRect holeRect = [holeRectValue CGRectValue]; 
     CGRect holeRectIntersection = CGRectIntersection(holeRect, rect); 

     CGContextRef context = UIGraphicsGetCurrentContext(); 

     if(CGRectIntersectsRect(holeRectIntersection, rect)) 
     { 
      CGContextAddEllipseInRect(context, holeRectIntersection); 
      CGContextClip(context); 
      CGContextClearRect(context, holeRectIntersection); 
      CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); 
      CGContextFillRect(context, holeRectIntersection); 
     } 
    } 
} 
+0

谢谢!这很好! – evenodd 2014-12-31 03:44:15

+3

@mosib这不会画多于一个圈子 – 2015-03-06 04:11:00

+0

@ xs2bush你找到任何解决方案绘制多个圈子 – iOS 2017-03-08 14:53:30

5

@ mosib的回答是一个很大的帮助我,直到我想在我的视图中绘制一个以上的圆形切口。奋力一点点后,我更新了我的drawRect像这样(在迅速...对不起坏编辑代码):

override func drawRect(rect: CGRect) 
{  
    backgroundColor.setFill() 
    UIRectFill(rect) 

    let layer = CAShapeLayer() 
    let path = CGPathCreateMutable() 

    for aRect in self.rects 
    { 
     let holeEnclosingRect = aRect 
     CGPathAddEllipseInRect(path, nil, holeEnclosingRect) // use CGPathAddRect() for rectangular hole 
     /* 
     // Draws only one circular hole 
     let holeRectIntersection = CGRectIntersection(holeRect, rect) 
     let context = UIGraphicsGetCurrentContext() 

     if(CGRectIntersectsRect(holeRectIntersection, rect)) 
     { 
     CGContextBeginPath(context); 
     CGContextAddEllipseInRect(context, holeRectIntersection) 
     //CGContextDrawPath(context, kCGPathFillStroke) 
     CGContextClip(context) 
     //CGContextClearRect(context, holeRectIntersection) 
     CGContextSetFillColorWithColor(context, UIColor.clearColor().CGColor) 
     CGContextFillRect(context, holeRectIntersection) 
     CGContextClearRect(context, holeRectIntersection) 
     }*/ 
    } 
    CGPathAddRect(path, nil, self.bounds) 
    layer.path = path 
    layer.fillRule = kCAFillRuleEvenOdd 
    self.layer.mask = layer 

} 
11

我用UIBezierPath处理切割出透明窟窿。 下面的代码进入你想画一个透明的孔UIView的子类:

- (void)drawRect:(CGRect)rect { 
    [super drawRect:rect]; 

    CGContextRef context = UIGraphicsGetCurrentContext(); 
    // Clear any existing drawing on this view 
    // Remove this if the hole never changes on redraws of the UIView 
    CGContextClearRect(context, self.bounds); 

    // Create a path around the entire view 
    UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:self.bounds]; 

    // Your transparent window. This is for reference, but set this either as a property of the class or some other way 
    CGRect transparentFrame; 
    // Add the transparent window 
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:transparentFrame cornerRadius:5.0f]; 
    [clipPath appendPath:path]; 

    // NOTE: If you want to add more holes, simply create another UIBezierPath and call [clipPath appendPath:anotherPath]; 

    // This sets the algorithm used to determine what gets filled and what doesn't 
    clipPath.usesEvenOddFillRule = YES; 
    // Add the clipping to the graphics context 
    [clipPath addClip]; 

    // set your color 
    UIColor *tintColor = [UIColor blackColor]; 

    // (optional) set transparency alpha 
    CGContextSetAlpha(context, 0.7f); 
    // tell the color to be a fill color 
    [tintColor setFill]; 
    // fill the path 
    [clipPath fill]; 
} 
+1

这真是一个很好的答案,因为UIBezierPath给予了很大的灵活性! 只需要注意一点:要使其工作,请将视图标记为非透明(无论是在IB还是通过代码) – mlepicki 2015-08-18 11:22:41

1

此实现支持矩形和圆形,写在迅速: PartialTransparentMaskView

class PartialTransparentMaskView: UIView{ 
    var transparentRects: Array<CGRect>? 
    var transparentCircles: Array<CGRect>? 
    weak var targetView: UIView? 

    init(frame: CGRect, backgroundColor: UIColor?, transparentRects: Array<CGRect>?, transparentCircles: Array<CGRect>?, targetView: UIView?) { 
     super.init(frame: frame) 

     if((backgroundColor) != nil){ 
      self.backgroundColor = backgroundColor 
     } 

     self.transparentRects = transparentRects 
     self.transparentCircles = transparentCircles 
     self.targetView = targetView 
     self.opaque = false 
    } 

    required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func drawRect(rect: CGRect) { 
     backgroundColor?.setFill() 
     UIRectFill(rect) 

     // clear the background in the given rectangles 
     if let rects = transparentRects { 
      for aRect in rects { 

       var holeRectIntersection = CGRectIntersection(aRect, rect) 

       UIColor.clearColor().setFill(); 
       UIRectFill(holeRectIntersection); 
      } 
     } 

     if let circles = transparentCircles { 
      for aRect in circles { 

       var holeRectIntersection = aRect 

       let context = UIGraphicsGetCurrentContext(); 

       if(CGRectIntersectsRect(holeRectIntersection, rect)) 
       { 
        CGContextAddEllipseInRect(context, holeRectIntersection); 
        CGContextClip(context); 
        CGContextClearRect(context, holeRectIntersection); 
        CGContextSetFillColorWithColor(context, UIColor.clearColor().CGColor) 
        CGContextFillRect(context, holeRectIntersection); 
       } 
      } 
     } 
    } 
} 
1

这里是我的一般的快速实施。

  • 对于静态的观点加元组到holeViews阵列(theView,isRound)
  • 如果你想动态分配的意见,因为我需要,设置生成的东西,说也许{someViewArray.map{($0,false)}} // array of views, not round
  • 使用如果需要,视图的角半径而不是isRound标志,isRound只是更容易制作圆圈。
  • 请注意,isRound is really isEllipseThatWillBeRoundIfTheViewIsSquare
  • 大多数代码不需要公共/内部的。

希望它可以帮助别人,这要感谢其他贡献者

public class HolyView : UIView { 
    public var holeViews = [(UIView,Bool)]() 
    public var holeViewsGenerator:(()->[(UIView,Bool)])? 

    internal var _backgroundColor : UIColor? 
    public override var backgroundColor : UIColor? { 
     get {return _backgroundColor} 
     set {_backgroundColor = newValue} 
    } 

    public override func drawRect(rect: CGRect) { 
     if (backgroundColor == nil) {return} 

     let ctxt = UIGraphicsGetCurrentContext() 

     backgroundColor?.setFill() 
     UIRectFill(rect) 

     UIColor.whiteColor().setFill() 
     UIRectClip(rect) 

     let views = (holeViewsGenerator == nil ? holeViews : holeViewsGenerator!()) 
     for (view,isRound) in views { 
      let r = convertRect(view.bounds, fromView: view) 
      if (CGRectIntersectsRect(rect, r)) { 
       let radius = view.layer.cornerRadius 
       if (isRound || radius > 0) { 
        CGContextSetBlendMode(ctxt, kCGBlendModeDestinationOut); 
        UIBezierPath(roundedRect: r, 
           byRoundingCorners: .AllCorners, 
           cornerRadii: (isRound ? CGSizeMake(r.size.width/2, r.size.height/2) : CGSizeMake(radius,radius)) 
        ).fillWithBlendMode(kCGBlendModeDestinationOut, alpha: 1) 
       } 
       else { 
        UIRectFillUsingBlendMode(r, kCGBlendModeDestinationOut) 
       } 
      } 
     } 

    } 
} 
1

如果你想要快速和有效,我添加了一个库(TAOverlayView)来的CocoaPods,允许你创建矩形/圆形覆盖允许用户与叠加层后面的视图进行交互。我用它来为我们的应用程序创建一个本教程:

Tutorial using the TAOverlayView

您可以通过一些设置覆盖的backgroundColorUIColor(red: 0, green: 0, blue: 0, alpha: 0.85),这取决于你的颜色和不透明需要改变的背景。

在此代码
+1

这实际上是一个非常适合我的甜蜜解决方案。 – flohei 2016-03-30 13:14:09

+0

但它不支持iOS 7 :( – 2016-07-21 12:22:27

0

创建大于圆更

- (void)drawRect:(CGRect)rect { 

    // Drawing code 
    UIColor *bgcolor=[UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0f];//Grey 

    [bgcolor setFill]; 
    UIRectFill(rect); 

    if(!self.initialLoad){//If the view has been loaded from next time we will try to clear area where required.. 

     // clear the background in the given rectangles 
     for (NSValue *holeRectValue in _rectArray) { 
      CGContextRef context = UIGraphicsGetCurrentContext(); 

      CGRect holeRect = [holeRectValue CGRectValue]; 

      [[UIColor clearColor] setFill]; 

      CGRect holeRectIntersection = CGRectIntersection(holeRect, rect); 

      CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); 
      CGContextSetBlendMode(context, kCGBlendModeClear); 

      CGContextFillEllipseInRect(context, holeRectIntersection); 

     } 
    } 

    self.initialLoad=NO; 
} 
+0

@ xs2bush请检查我的代码 – iOS 2017-03-09 06:23:20

2

另一种解决方案: 大矩形是所有的视图(黄色)和小是透明RECT。 颜色不透明度可设置。

let pathBigRect = UIBezierPath(rect: bigRect) 
    let pathSmallRect = UIBezierPath(rect: smallRect) 

    pathBigRect.appendPath(pathSmallRect) 
    pathBigRect.usesEvenOddFillRule = true 

    let fillLayer = CAShapeLayer() 
    fillLayer.path = pathBigRect.CGPath 
    fillLayer.fillRule = kCAFillRuleEvenOdd 
    fillLayer.fillColor = UIColor.yellowColor().CGColor 
    //fillLayer.opacity = 0.4 
    view.layer.addSublayer(fillLayer) 

enter image description here

0

包括利用C#Xamarin工作室的iOS答案。这绘制了一个具有60%Alpha的圆角矩形。大部分来自@mikeho的答案

public override void Draw(CGRect rect) 
{ 
    base.Draw(rect); 

    //Allows us to draw a nice clear rounded rect cutout 
    CGContext context = UIGraphics.GetCurrentContext(); 

    // Create a path around the entire view 
    UIBezierPath clipPath = UIBezierPath.FromRect(rect); 

    // Add the transparent window to a sample rectangle 
    CGRect sampleRect = new CGRect(0f, 0f, rect.Width * 0.5f, rect.Height * 0.5f); 
    UIBezierPath path = UIBezierPath.FromRoundedRect(sampleRect, sampleRect.Height * 0.25f); 
    clipPath.AppendPath(path); 

    // This sets the algorithm used to determine what gets filled and what doesn't 
    clipPath.UsesEvenOddFillRule = true; 

    context.SetFillColor(UIColor.Black.CGColor); 
    context.SetAlpha(0.6f); 

    clipPath.Fill(); 
}