0

First of all, i've looked for and found this: Cut transparent hole in UIView Putting multiple transparent rectangles on my view, but now I need these rectangles to be rounded, like this: http://postimg.org/image/ozxr0m5sh/ So I mixed some codes I found and did that, but for some reason it only works for the first rectangle, here is the full code for the custom view: (if you take off the method "addRoundedRect..." call, it works for all the rects).

- (void)drawRect:(CGRect)rect{

[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 );
    CGContextRef context = UIGraphicsGetCurrentContext();

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

}

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight){
    float fw, fh;
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect),        CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(context, fw, fh/2);
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}
Community
  • 1
  • 1

2 Answers2

1

In iOS it's generally better not to use drawRect. It tends to be slower than other methods of rendering your content.

I don't know the specific answer to your question about why you can't punch multiple round-edged holes in your view, but I would suggest a different approach. than mucking around with CGContexts in your drawRect method.

Set up your view with whatever content you need. Then create a CAShapeLayer the same size as your view and fill it with a path (shape layers want a CGPath, but you can create a UIBezierPath and get a CGPath from that.) Attach the shape layer as the mask of your view's layer. (The shape you put in your mask layer defines the opaque parts of your view, though, so you have to create a shape that fills the mask and then punch holes in it with other shapes.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
0

here I had a crack. UserInteraction must be turned off on this view in order to pass touch events through, so don't add any subviews here unless you want them to ignore touch as well..

interface:

#import "AslottedView.h"
//header is empty but for #import <UIKit/UIKit.h>
//this is a subclass on UIView
@interface AslottedView ()

//helper function, nb resultantPath will rerquire releasing(create in func name)
CGMutablePathRef CGPathCreateRoundedRect(CGRect rect, CGFloat cornerRadius);


@end

implementation:

@implementation AslottedView
{
  CGRect slots[4];
}

CGMutablePathRef CGPathCreateRoundedRect(CGRect rect, CGFloat cornerRadius){

  CGMutablePathRef result = CGPathCreateMutable();

  CGPathMoveToPoint(result, nil, CGRectGetMinX(rect)+cornerRadius, (CGRectGetMinY(rect)) );

  CGPathAddArc(result, nil, (CGRectGetMinX(rect)+cornerRadius), (CGRectGetMinY(rect)+cornerRadius), cornerRadius, M_PI*1.5, M_PI*1.0, 1);//topLeft
  CGPathAddArc(result, nil, (CGRectGetMinX(rect)+cornerRadius), (CGRectGetMaxY(rect)-cornerRadius), cornerRadius, M_PI*1.0, M_PI*0.5, 1);//bottomLeft
  CGPathAddArc(result, nil, (CGRectGetMaxX(rect)-cornerRadius), (CGRectGetMaxY(rect)-cornerRadius), cornerRadius, M_PI*0.5, 0.0, 1);//bottomRight
  CGPathAddArc(result, nil, (CGRectGetMaxX(rect)-cornerRadius), (CGRectGetMinY(rect)+cornerRadius), cornerRadius, 0.0, M_PI*1.5, 1);//topRight
  CGPathCloseSubpath(result);
  return result;

}

CGColorRef fillColor(){

  return [UIColor whiteColor].CGColor;
  //or whatever..
}

-(instancetype )initWithFrame:(CGRect)frame{

  if (self = [super initWithFrame:frame]) {

    self.userInteractionEnabled = NO;
    self.backgroundColor = [UIColor clearColor];

 //quick loop to make some rects
    CGRect rct = CGRectMake(10.0, 10.0, 40.0, 40.0);
    CGFloat margin = 30.0;

    for (NSInteger i = 0; i < 4; i ++) {

      slots[i] = CGRectOffset(rct, ((rct.size.width+margin) * ((i%2==0)? 1.0 : 0.0))  , ((rct.size.height+margin) * ((i>1)? 1.0:0.0) )) ;
    }
  }
  return self;
}




- (void)drawRect:(CGRect)rect {

  CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGContextSetFillColorWithColor(ctx, fillColor() );

  CGContextAddRect(ctx, self.bounds);
  for (NSInteger i = 0; i < 4; i ++) {

    CGMutablePathRef roundRect = CGPathCreateRoundedRect(slots[i], 5.0);
    CGContextAddPath(ctx, roundRect);
    CGPathRelease(roundRect);

  }
  CGContextEOFillPath(ctx);

}


@end
Jef
  • 4,728
  • 2
  • 25
  • 33