Drawing multiple arcs using Core Graphics - core-graphics

I'm trying to draw two concentric circles using Core Graphics. I would expect the following code to draw a blue circle and a smaller white circle inside, however it just draws the blue circle. What am I missing?
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextAddArc(c, self.bounds.size.width/2, self.bounds.size.height/2, 100, 0, M_PI * 2, true);
CGContextSetFillColor(c, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextFillPath(c);
CGContextAddArc(c, self.bounds.size.width/2, self.bounds.size.height/2, 90, 0, M_PI * 2, true);
CGContextSetFillColor(c, CGColorGetComponents([[UIColor whiteColor] CGColor]));
CGContextFillPath(c);

You are setting the fill color in an unnecessarily indirect way. Do this instead:
CGContextAddArc(c, self.bounds.size.width/2, self.bounds.size.height/2, 100, 0, M_PI * 2, true);
CGContextSetFillColorWithColor(c, [[UIColor blueColor] CGColor]);
CGContextFillPath(c);
CGContextAddArc(c, self.bounds.size.width/2, self.bounds.size.height/2, 90, 0, M_PI * 2, true);
CGContextSetFillColorWithColor(c, [[UIColor whiteColor] CGColor]);
CGContextFillPath(c);
Or, even better, just use UIKit's drawing methods directly:
[[UIColor blueColor] setFill];
[[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2) radius:100 startAngle:0 endAngle:M_PI * 2 clockwise:YES] fill];
[[UIColor whiteColor] setFill];
[[UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2) radius:90 startAngle:0 endAngle:M_PI * 2 clockwise:YES] fill];
Your code is failing because [[UIColor whiteColor] CGColor] returns a color in the "gray" colorspace, which has only two components, a "gray" value (0 for black, 1 for white) and an alpha value. In this case, the context is RGBA, so CGContextSetFillColor expects to see 4 components, three for RGB and one for alpha.
The documentation for CGContextSetFillColor points out:
Note that the preferred API to use is now
CGContextSetFillColorWithColor.

Related

How to set the Radius Corners to View using DrawRect Method?

using DrawRect method to draw a rectangle view. I have to set the radius corners of that particular rectangle view.I have written to draw a rectangle view below.
- (void)drawRect:(CGRect)rect {
int coordinate_x=60,coordinate_y=120,width=200,height=295;
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect drawTank = {coordinate_x, coordinate_y, width, height};
CGColorRef blackColor=[UIColor blackColor].CGColor;
CGContextSetRGBStrokeColor(context, 0, 0, 255, 1);
CGContextSetLineWidth(context, 1.0);
CGContextSetStrokeColorWithColor(context, blackColor);
CGContextStrokeRect(context, drawTank);
}
And i have to use fill the view and empty view use code below.
CGRect emptyTank = CGRectMake(coordinate_x, coordinate_y, width, height *(1-filledPercentage));
CGRect fullTank = CGRectMake(coordinate_x, coordinate_y+height *(1-filledPercentage),width, height * filledPercentage);
how to set the radius corner to the particular view. please help me.
Thanks in Advance.
you can simply set the corner radius of a UIView with:
view.layer.cornerRadius = 5;
If you are using beizer path , you can set corner radius with the following code:
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(55, 30, 133, 51) cornerRadius: 5];
[UIColor.grayColor setFill];
[rectanglePath fill];
within the drawRect method:
- (void)drawRect: (CGRect)frame
{
//// Rectangle Drawing
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(CGRectGetMinX(frame) + 40, CGRectGetMinY(frame) + 21, 133, 51) cornerRadius: 7];
[UIColor.grayColor setFill];
[rectanglePath fill];
}

Adding Bezier path to CGPath: ObjectiveC

I have a rectangle drawn using drawRect method.
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect outline = CGRectMake(4, 4, width - 8, height - 8);
CGColorRef white = [[UIColor whiteColor] CGColor];
CGColorRef black = [[UIColor blackColor] CGColor];
CGContextSetFillColorWithColor(context, white);
CGContextFillEllipseInRect(context, outline);
CGContextSetLineWidth(context, 2.0f);
CGContextSetStrokeColorWithColor(context, black);
CGContextStrokeEllipseInRect(context, outline);
I have a bezier path drawn in the samedrawn rect method.
[[UIColor blackColor] setStroke];
[[UIColor whiteColor] setFill];
UIBezierPath * path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addQuadCurveToPoint:point3 controlPoint:point2];
[path addQuadCurveToPoint:point5 controlPoint:point4];
[path setLineWidth:2.0f];
[path stroke];
[path fill];
I need to add a CALayer over these two shapes so that they appear as one.
aPath = CGPathCreateMutable();
CGPathAddEllipseInRect(aPath, nil, outline);
CGPathCloseSubpath(aPath);
pathCopy = CGPathCreateCopyByTransformingPath(aPath, nil);
myLayer = nil;
myLayer = [CAShapeLayer layer];
myLayer.path = pathCopy;
myLayer.fillColor = [[UIColor whiteColor] CGColor];
[self.layer addSublayer:myLayer];
The problem is that I cant add the bezier path to the CGPath. That's one.
Another one is that I cant add a border color or border width to the layer which I am creating. Can anyone help?
Try:
CGPathAddPath(aPath, nil, path.CGPath);
Where aPath is your mutable CGPath and path is your UIBezierPath.

Core graphics draw rectangle with border in one line

How can I draw a rectangle with a border in one line?
There are separate methods like:
CGContextStrokeRect(context, someRectangle);
and
CGContextFillRect(context, someRectangle);
but is there something that does both in one?
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGPathRef path = CGPathCreateWithRect(rect, NULL);
[[UIColor redColor] setFill];
[[UIColor greenColor] setStroke];
CGContextAddPath(context, path);
CGContextDrawPath(context, kCGPathFillStroke);
CGPathRelease(path);
}
Although, I can't say it's any less verbose than stroke & fill in separate calls...
If you're just looking to save line space, you could define your own method to make two calls and place it in a utility class.
void strokeAndFill(CGContextRef c, CGRect rect)
{
CGContextFillRect(c, rect);
CGContextStrokeRect(c, rect);
}
CGContextDrawPath does it one go if you set fill and stroke color beforehand.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColor(context, a);
CGContextSetFillColor(context, b);
CGContextDrawPath(context, rect)

UITableView with static cell - different separation color per section?

I have UITableView with static cells in 4 sections done in Storyboard. However, I want to change the separator color for one section ([UIColor clearColor]). How can I do that??? Is it actually possible?
I can set the separatorColor to clearColor for the entire table, but not only for one specific section.
Screenshot of table view section:
AFAIK there is no method for this. But you can put a background image to the cell which has a separator at the bottom and set separatorstyle to UITableViewCellSeparatorStyleNone. So you have your own separator in every cell.
Maybe you can achieve your goal by setting the header text for the section to an empty string.
One approach would to create your own UIView subclass and do your own custom drawing in drawRect:. You would take this view and add it as the backgroundView of your table view cell. Something like this:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1.0);
// Draw black line
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 0.0, 0.3};
CGColorRef blackColor = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, blackColor);
CGContextMoveToPoint(context, 0, rect.size.height - 1.5);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height - 1.5);
CGContextStrokePath(context);
CGColorRelease(blackColor);
// Draw white bottom line
CGFloat whiteComponents[] = {1.0, 1.0, 1.0, 0.75f};
CGColorRef whiteColor = CGColorCreate(colorspace, whiteComponents);
CGContextSetStrokeColorWithColor(context, whiteColor);
CGContextMoveToPoint(context, 0, rect.size.height - 0.5);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height - 0.5);
CGContextStrokePath(context);
CGColorRelease(whiteColor);
// Draw top white line
CGFloat whiteTransparentComponents[] = {1.0, 1.0, 1.0, 0.45};
CGColorRef whiteTransparentColor = CGColorCreate(colorspace, whiteTransparentComponents);
CGContextSetStrokeColorWithColor(context, whiteTransparentColor);
CGContextMoveToPoint(context, 0, 0.5);
CGContextAddLineToPoint(context, rect.size.width, 0.5);
CGContextStrokePath(context);
CGColorRelease(whiteTransparentColor);
CGColorSpaceRelease(colorspace);
}

CoreGraphics draw an image on a white canvas

I have a source image which has a variable width and height, which I must show on a fullscreen iPad UIImageView but with addition of borders around the image itself. So my task is to create a new image with a white border around it, but not overlapping on the image itself. I'm currently doing it with overlapping via this code:
- (UIImage*)imageWithBorderFromImage:(UIImage*)source
{
CGSize size = [source size];
UIGraphicsBeginImageContext(size);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
[source drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 40.0);
CGContextStrokeRect(context, rect);
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}
Can anyone tell me how do I first draw a white canvas that is 40 pixels bigger in each direction than the source image and then draw that image on it?
I adjusted your code to make it work. Basically what it does:
Set canvas size to the size of your image + 2*margins
Fill the whole canvas with background color (white in your case)
Draw your image in the appropriate rectangle (with initial size and required margins)
Resulting code is:
- (UIImage*)imageWithBorderFromImage:(UIImage*)source
{
const CGFloat margin = 40.0f;
CGSize size = CGSizeMake([source size].width + 2*margin, [source size].height + 2*margin);
UIGraphicsBeginImageContext(size);
[[UIColor whiteColor] setFill];
[[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, size.width, size.height)] fill];
CGRect rect = CGRectMake(margin, margin, size.width-2*margin, size.height-2*margin);
[source drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return testImg;
}