57

I am still struggling with drawing a line with CGContext. I have actually go to line to draw, but now I need the background of the Rect to be transparent so the existing background shows thru. Here's my test code:

(void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
    CGContextSetAlpha(context,0.0);
    CGContextFillRect(context, rect);

    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextSetLineWidth(context, 5.0);
    CGContextMoveToPoint(context, 100.0,0.0);
    CGContextAddLineToPoint(context,100.0, 100.0);
    CGContextStrokePath(context);
}

Any ideas?

Codebeef
  • 43,508
  • 23
  • 86
  • 119
Jim B
  • 2,267
  • 6
  • 24
  • 26

8 Answers8

75

After UIGraphicsGetCurrentContext() call CGContextClearRect(context,rect)

Edit: Alright, got it.

Your custom view with the line should have the following:

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self setBackgroundColor:[UIColor clearColor]];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextClearRect(context, rect);
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextSetLineWidth(context, 5.0);
    CGContextMoveToPoint(context, 100.0,0.0);
    CGContextAddLineToPoint(context,100.0, 100.0);
    CGContextStrokePath(context);
}

My test used this as a very basic UIViewController:

- (void)viewDidLoad {
    [super viewDidLoad];
    UIImageView *v = [[UIImageView alloc] initWithFrame:self.view.bounds];
    [v setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:v];
    TopView *t = [[TopView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:t];
    [v release];
    [t release];
}
David Kanarek
  • 12,611
  • 5
  • 45
  • 62
  • 8
    Background is black, must be the iphone background. I'm actually trying to draw on top of a UIView. – Jim B Jan 24 '10 at 02:28
  • I don't quite follow. Are you sure you added the UIView to the superview? Is this drawRect in the UIView you want to draw on top of, or in a different one? Did you set a background color for this UIView accidentally? – David Kanarek Jan 24 '10 at 03:04
  • Thanks for the questions. I would expect that IM added the UIView to it's superview. The draw rectangle is definitely in the view, since the line was drawn properly. Yes I have set a background into the UIView, it's that background I want to show thru. All I'm trying to do is draw a line on top of an existing view. Frustrated in Seattle. – Jim B Jan 24 '10 at 13:39
  • Clear Rect doesn't do it here. – Stephen J Aug 16 '13 at 19:02
45

Easy way:

- (id)initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {       
        self.opaque = NO;
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextClearRect(context, rect);
    //your code
}
ZGl6YXNt
  • 1,814
  • 18
  • 17
  • 4
    I am using this for an accessory indicator in a table view cell. self.opaque = NO works while [self setBackgroundColor:[UIColor clearColor]] in the accepted answer does not. – T.J. Apr 08 '14 at 22:33
  • self.opaque = false helped me out when creating a custom sub view of a UICollectionViewCell – ae14 Nov 27 '15 at 05:01
  • 1
    This should be an accepted answer. self.opaque = NO makes the view using drawRect, transparent. Thank you! – Michael May 06 '16 at 10:10
7

Init a context with opaque == false, Swift 3

UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) 

opaque

A Boolean flag indicating whether the bitmap is opaque. If you know the bitmap is fully opaque, specify true to ignore the alpha channel and optimize the bitmap’s storage. Specifying false means that the bitmap must include an alpha channel to handle any partially transparent pixels.

onmyway133
  • 45,645
  • 31
  • 257
  • 263
  • This was my issue, too. The layer on screen was transparent despite `isOpaque` being true. So I dropped `self.isOpaque` as second parameter and wondered why the resulting `UIImage` was not. – heyfrank Oct 17 '18 at 12:39
  • Don't forget to close the context to avoid memory leaks: `UIGraphicsEndImageContext()` – Bocaxica Jan 22 '21 at 11:19
4

This is what worked for me with a UIImage which had been manually added using InterfaceBuilder.

- (id)initWithCoder:(NSCoder *)aDecoder {

    if(self = [super initWithCoder:aDecoder]) {
        self.backgroundColor = [UIColor clearColor];
    }

    return self;
}


-(void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();    
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextSetLineWidth(context, 5.0);
    CGContextMoveToPoint(context, 100.0,0.0);
    CGContextAddLineToPoint(context,100.0, 100.0);
    CGContextStrokePath(context);
}

David Kanarek's answer only works when you're manually creating your own UIImageView. If you've created a UIView and manually added it via Interface Builder then you will need a different approach like this calling the initWithCoder method instead.

Patrick Collins
  • 4,046
  • 3
  • 26
  • 29
3

I have the same problem, then I find it is. I overwrite the init Method is -(id)initWithFrame:(CGRect)rect. In this method self.background = [UIColor clearColor]; but i use this view in xib file !!! That will call the init method is

-(id)initWithCoder:(NSCoder*)aDecoder;

So overwrite all the init Method and setup BackgroundColor will work OK.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
2
CGContextClearRect(context,rect) 

If the provided context is a window or bitmap context, Quartz effectively clears the rectangle. For other context types, Quartz fills the rectangle in a device-dependent manner. However, you should not use this function in contexts other than window or bitmap contexts.

Codrut
  • 35
  • 1
1

you can create a image context with this code:

cacheContext = CGBitmapContextCreate (cacheBitmap, size.width, size.height, 8, bitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
CGContextSetRGBFillColor(cacheContext, 0, 0, 0, 0);
CGContextFillRect(cacheContext, (CGRect){CGPointZero, size});

the key is kCGImageAlphaPremultipliedLast.

fluke
  • 660
  • 8
  • 16
0

Having trouble understanding the question here, but if you're unable to have a "background" UIView show through a "top" view into which you're drawing, one solution is topView.backgroundColor = [UIColor clearColor]; I was having (I think) this same problem and this solved it for me.

oflannabhra
  • 661
  • 5
  • 18