I am trying to draw some graphics elements in a UIView inside drawRect method. Code is attached, when I run this code the circle filled with color makes other line disappear.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, x, y);
CGRect rectangle = CGRectMake(60+x,100+y,100,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextFillEllipseInRect(context, rectangle);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
Please help
Having the same problem. Closer look at documentation on CGContextFillEllipseInRect function has totally disappointed me:
Discussion
As a side effect when you call this function, Quartz clears the
current path
https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGContext/Reference/reference.html#//apple_ref/c/func/CGContextFillEllipseInRect
Related
I am drawing a simple filled circle using following code in draw rect.
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con, CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height));
CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
CGContextFillPath(con);
it draws a circle properly. Now I want to clip the circle with another small circle in the middle so that it becomes a hollow circle and you can see whatever is behind the main circle. How can i do that?
Use the even-odd rule with CGContextEOClip()
CGSize size = rect.size;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, 0);
CGContextSaveGState(context);
CGContextAddPath(context, ([UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, size.width, size.height)].CGPath));
CGContextAddPath(context, ([UIBezierPath bezierPathWithOvalInRect:CGRectMake(size.width/4, size.height/4, size.width/2, size.height/2)].CGPath));
CGContextEOClip(context); //clip
CGContextAddPath(context, [UIBezierPath bezierPathWithRect:rect].CGPath);
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGContextFillPath(context);
CGContextRestoreGState(context);
I was able to do that using the EO rule.
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con, rect);
CGContextAddEllipseInRect(con, CGRectInset(rect, 40, 40));
CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
CGContextEOFillPath(con);
So, I have this code, that draws a circle with a line around it.
- (void)drawRect:(CGRect)rect
{
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, 40.0);
CGContextSetRGBFillColor(contextRef, 0.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(contextRef, 132.0/255.0, 128.0/255.0, 128.0/255.0, 1.0);
CGContextFillEllipseInRect(contextRef, rect);
CGContextStrokeEllipseInRect(contextRef, rect);
}
The problem is that half of the width of the line falls outside the rect.
So, what I would like to do, is to create an inset relative to the line width, to compensate for this.
Or maybe there is a method, that tells my line to remain inside the boundaries of the circle?
Before filling,
rect = CGRectInset(rect, 1, 1);
This code results in the image below. As far as I understand CGContextClipToMask, the red rectangle should not be visible, since it is outside of the clipped area. What am I missing here? Thanks for any help!
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextFillRect(context, rect);
CGContextSetLineWidth(context, 20);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
// draw partial circle
UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:NO];
CGContextAddPath(context, [arc CGPath]);
CGContextStrokePath(context);
// create mask
CGImageRef mask = CGBitmapContextCreateImage(context);
self.maskCreated(mask);
// save state
CGContextSaveGState(context);
// clip with mask
CGContextClipToMask(context, rect, mask);
// draw test rect
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, CGRectMake(0, 0, 100, 100));
// restore state
CGContextRestoreGState(context);
The documentation for CGContextClipToMask says:
If mask is an image, then it must be in the DeviceGray color space,
may not have an alpha component, and may not be masked by an image
mask or masking color.
I'm assuming your code is in a the -drawRect: method of a subclass of UIView, so you are using the CGContext which was provided to you, which is in an RGB color space and probably has an alpha component. Your mask image is created from that context, so it gets the same attributes.
To fix this, use a separate bitmap context to generate the mask, using a gray colorspace with no alpha. Here's a self-contained example that does something similar to your code.
- (void)drawRect:(CGRect)rect
{
// Create a context for the mask
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef maskContext = CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, 8, 0, colorSpace, kCGImageAlphaNone | kCGBitmapByteOrderDefault);
CGColorSpaceRelease(colorSpace);
// Fill with black
CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor);
CGContextFillRect(maskContext, rect);
// Draw an arc in white
CGContextSetLineWidth(maskContext, 20);
CGContextSetStrokeColorWithColor(maskContext, [UIColor whiteColor].CGColor);
CGContextAddArc(maskContext, CGRectGetMidX(rect), CGRectGetMidY(rect), 50, M_PI, 0, false);
CGContextStrokePath(maskContext);
// Create the mask image from the context, and discard the context
CGImageRef mask = CGBitmapContextCreateImage(maskContext);
CGContextRelease(maskContext);
// Now draw into the view itself
CGContextRef context = UIGraphicsGetCurrentContext();
// Apply the mask
CGContextClipToMask(context, rect, mask);
// Then draw something that overlaps the mask
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
// Make sure to clean up when we're done
CGImageRelease(mask);
}
Actually don't understand your concern, but you can hide rectangle in your method like this:
// draw a test rect
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGRect rect = CGRectZero;
CGContextFillRect(context, rect);
I'm having trouble with drawing a line on the map with a stroke. (inside color and outside color) I beleive i'm on the right path and have subclassed mkOverlayView to override the drawing (needs to fill with the road size) so inside drawMapRect...
CGFloat lineWidth = MKRoadWidthAtZoomScale(zoomScale);
MKMapRect clipRect = MKMapRectInset(mapRect, -lineWidth, -lineWidth);
...
CGContextAddPath(context, path);
CGContextSetStrokeColorWithColor(context, line.color.CGColor);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextSetAlpha(context, 0.4f);
CGContextStrokePath(context);
CGPathRelease(path);
I'm not sure how to add the stroke. Any help would be greatly appreciated. xcode 4.6 / ios 6.0+
stroke first a path ( road with) with color 1, then change stroke width and color to a thinner line with road with * 0.6 in color 2, and stroke again.
Ok, I managed to figure it out based on Mathew's suggestion but with a few tweaks...
Essentially I created a stroked path using CGPathCreateCopyByStrokingPath and made the stroke slightly darker than the base color. Then created a transparentLayer with the path and stroke, used the blend mode kCGBlendModeDestinationAtop and drew another path with only a fill this time on top. I'm not sure if this is the best approach but appears to work well.
CGPathRef newpath = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, kCGLineCapRound, kCGLineJoinMiter, 0.0);
CGContextAddPath(context, newpath);
CGContextSetStrokeColorWithColor(context, line.color.CGColor);
CGContextSetFillColorWithColor(context, line.color.CGColor);
CGContextSetLineWidth(context, lineWidth * 0.3);
CGContextSetAlpha(context, 0.8f);
CGContextBeginTransparencyLayer (context, NULL);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextAddPath(context, newpath);
CGContextFillPath(context);
CGContextEndTransparencyLayer(context);
CGContextSetBlendMode(context, kCGBlendModeDestinationAtop);
CGContextSetAlpha(context, 0.3f);
CGContextBeginPath(context);
CGContextAddPath(context, newpath);
CGContextFillPath(context);
CGPathRelease(path);
CGPathRelease(newpath);
EDIT Here is a simpler solution based on AlexWien's approach
if (path != nil)
{
CGPathRef path2 = CGPathCreateCopy(path);
CGFloat hue;
CGFloat saturation;
CGFloat brightness;
CGFloat alpha;
[line.color getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];
UIColor *c2 =[UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:0.4];
CGContextAddPath(context, path);
CGContextSetStrokeColorWithColor(context, c2.CGColor);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextStrokePath(context);
CGPathRelease(path);
CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
CGContextAddPath(context, path2);
CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 0.3f);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth/2.0f);
CGContextStrokePath(context);
CGPathRelease(path2);
}
I am trying to make a line graph using the drawRect method but I have came across a major problem. The 0 point on the iPhone screen is in the top left corner. Is there any way to either relocate the 0,0 point or change the coordinates input to where they would be if the 0,0 point was in the bottom left corner?
Heres My drawRect method
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
//Coordinates of bottom left corner (480 went off screen)
CGContextMoveToPoint(context, 0, 460);
CGContextAddLineToPoint(context, 320, 0);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
This page describes how to treat it as a right-hand coordinate system instead of a left-hand, which sounds like what you want