How to fill outside overlay circle in iOS 7 on map - ios

I need the same filled space around circle on the map as in Reminders app in iOS7. I think need to use the method applyFillPropertiesToContext:atZoomScale or fillPath:inContext:.

I solved my problem:
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
// Fill full map rect with some color.
CGRect rect = [self rectForMapRect:mapRect];
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:0.0 alpha:0.4f].CGColor);
CGContextFillRect(context, rect);
CGContextRestoreGState(context);
// Clip rounded hole.
CGContextSaveGState(context);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillEllipseInRect(context, [self rectForMapRect:[self.overlay boundingMapRect]]);
CGContextRestoreGState(context);
// Draw circle
[super drawMapRect:mapRect zoomScale:zoomScale inContext:context];
}

Related

How to clear circle in CGContext in iOS

I want create image using CGcontext. This is simple image with white or black background. also I want to add transperent part which is in circle ( check attached image). I know how to do this in rect. But i want to make it circle. Please anyone help me in this.
Use the below code to clear circle in your context
-(UIImage *) getImageWithcenterClear:(CGPoint) center{
CGRect frame = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContextWithOptions([[UIScreen mainScreen] bounds].size,
NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5 ] CGColor]);
CGContextFillRect(context, frame);
float radius = 50 * 2;
// Clear Circle
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextAddArc(context, center.x, center.y, radius - 0.54, 0, 2 * M_PI, 0);
CGContextDrawPath(context, kCGPathFill);
CGContextSetBlendMode(context, kCGBlendModeNormal);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

Drawing a Hollow Circle with Core Graphics for iOS

I am looking for the way how to draw a hollow circle using Core Graphics (CGContext) in iOS. I tried to do it using the code:
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 8.0);
CGContextSetStrokeColor(ctx, CGColorGetComponents([[UIColor redColor] CGColor]));
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextFillEllipseInRect(ctx, rect);
CGContextFillPath(ctx);
}
but it draws the filled circle.
Since this question is over discussed here but other examples like this give me only filled circles.
If you want to draw a circle within the rect, using Stroke methods and the rect in parameter you will draw a part of the cercle outside the rect.
You then have two choices, assuming you know the width of the circle you want to draw.
First, you can stroke the line, but you have to draw it in a smaller rect :
-(void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat innerWidth = 8;
[[UIColor redColor] setStroke];
CGContextSetLineWidth(ctx, innerWidth);
// We add an ellipsis shifted by half the inner Width
CGContextAddEllipseInRect(ctx, CGRectInset(rect, innerWidth, innerWidth));
// Stroke the path
CGContextStrokePath(ctx);
}
You can also fill the circles using the even-odd rule (Apple docs)
-(void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat innerWidth = 8;
[[UIColor redColor] setStroke];
// Add the outer circle
CGContextAddEllipseInRect(ctx, rect);
// Add the inner circle
CGContextAddEllipseInRect(ctx, CGRectInset(rect, innerWidth, innerWidth));
// Fill the path using the EO rule
CGContextEOFillPath(ctx);
}
If you only want the circle outline, don't fill it.
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 8.0);
[[UIColor redColor] set];
CGContextStrokeEllipseInRect(ctx, rect);
}
Use CGContextStrokeEllipseInRect instead of CGContextFillEllipseInRect. And since you haven't built a path in the current context, get rid of CGContextFillPath.
One way you could do it is draw a filled circle and then draw a slightly smaller circle with CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear)
After your code add something like
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 5.0);
CGContextSetBlendMode(ctx,kCGBlendModeClear)
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextFillEllipseInRect(ctx, rect);
CGContextFillPath(ctx);
UIGraphicsEndImageContext();
I use CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear) in my drawing application, which is probably a better use. Stroking the path will probably work for you.

CGContextClipToMask does not clip

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

What is wrong with my CGContextclip.

I am beginner with Core Garphics and I am try to get around with my understanding of CGContextclip. I am doing a simple program with custom UIButton drawrect as below
Rect dimension passed to drawRect method is CustomButton *button = [[CustomButton alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
#implementation CustomButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef colorRef = [[UIColor blueColor] CGColor];
CGContextSetStrokeColorWithColor(context, colorRef);
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextSetLineWidth(context, 3.0f);
CGContextAddRect(context, rect);
CGContextStrokeRect(context, rect);
//CGContextFillRect(context, rect);
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextSetFillColorWithColor(context, [[UIColor redColor]CGColor]);
CGMutablePathRef rectPath = CGPathCreateMutable();
CGPathMoveToPoint(rectPath, NULL, CGRectGetMinX(rect), CGRectGetMidY(rect));
CGPathAddLineToPoint(rectPath, NULL, CGRectGetMaxX(rect), CGRectGetMidY(rect));
CGPathAddLineToPoint(rectPath, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGPathAddLineToPoint(rectPath, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGPathCloseSubpath(rectPath);
CGContextAddPath(context, rectPath);
CGContextClip(context);
CGContextStrokePath(context);
//CGContextFillPath(context);
CGContextRestoreGState(context);
CGColorRelease(colorRef);
}
#end
I am expecting a full rect with dimension (0,0,100,50) colored in blue and a half rect inside with red coloured. I am getting the blue colored rect but red colored rect is not visible in my context.
I have gone through some solution here and also at some blogs but to my faulty eyes the code looks simple and fine. What is wrong with my clipping.
Thank you for your time and response.
I think there's no path in the context anymore after you clipped it.Just fill another rectangle:
//CGContextFillPath(context);
CGContextFillRect(context, rect);

Make a line drawn with CoreGraphics dynamic

I am drawing a line using the following method:
- (void)drawLineWithColor:(UIColor *)color andRect: (CGRect)rect{
if (uploadButtonHidden == 2) {
uploadPhotoButton.hidden = NO;
}
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 15, 110);
// set the stroke color and width
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextSetLineWidth(context, 6.0);
// move to your first point
CGContextMoveToPoint(context, 455, coords.y - 140);
// add a line to your second point
CGContextAddLineToPoint(context, coordsFinal.x, coordsFinal.y);
// tell the context to draw the stroked line
CGContextStrokePath(context);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Draw image on view
[image drawAtPoint:CGPointZero];
}
As you can see coords.y sets the starting point of my line. Is there any way when changing the coords.y point to update my line? If for example I have a method which adds 50 to coords.y every 0.5 seconds, how can I update the line without redrawing it (to prevent a memory crash)??
EDIT:
this method is called like this:
UIGraphicsBeginImageContext(self.view.frame.size);
[self drawLineWithColor:[UIColor blackColor] andRect:CGRectMake(20, 30, 1476, 1965)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
imageViewForArrows = [[UIImageView alloc] initWithImage:image];
[imageArrowsArray addObject:imageViewForArrows];
Don't draw into an image, draw straight into the context instead. I'm assuming this method is called from within your drawRect method, in which case there will already be a value CGContextRef. You just have to get it and draw into it. Be sure to use CGContextSaveGState and CGContextRestoreGState when you apply a transform or clipping.
- (void)drawLineWithColor:(UIColor *)color andRect: (CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 15, 110);
// set the stroke color and width
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextSetLineWidth(context, 6.0);
// move to your first point
CGContextMoveToPoint(context, 455, coords.y - 140);
// add a line to your second point
CGContextAddLineToPoint(context, coordsFinal.x, coordsFinal.y);
// tell the context to draw the stroked line
CGContextStrokePath(context);
CGContextRestoreGState(context);
}

Resources