Core graphics draw rectangle with border in one line - objective-c

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)

Related

Draw lines in UIView not supported for multiple screen sizes?

I want to draw lines in a UIView with based the UIView's height. (i.e) line height should be equal to the UIView's height. For that i'm using the following code.
- (void)testDraw :(void(^)(UIImage *image, UIImage *selectedImage))done
{
CGSize imageSize = CGSizeMake(1000, self.bounds.size.height);
//Begin the animation by checking the screen is retina / ordinary
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0f);
else
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
for (NSInteger intSample=0; intSample < 1000; intSample++) {
if(intSample % self.samplesPerSecond == 0){
//draw separator line
[self drawLine:context fromPoint:CGPointMake(intSample, 0) toPoint:CGPointMake(intSample, self.frame.size.height) color:self.lineColor lineWidth:2.0];
}
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGRect drawRect = CGRectMake(0, 0, image.size.width, self.frame.size.height);
[self.progressColor set];
UIRectFillUsingBlendMode(drawRect, kCGBlendModeSourceAtop);
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
done(image, tintedImage);
}
//Draw the line based on the value received
- (void) drawLine:(CGContextRef) context fromPoint:(CGPoint) fromPoint toPoint:(CGPoint) toPoint color:(UIColor*) color lineWidth:(float) lineWidth{
CGContextBeginPath(context);
//add the lines with sizes that u want
CGContextSetAlpha(context,1.0);
CGContextSetLineWidth(context, lineWidth);
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
}
When i execute the above code with it working fine in 3.5 inch display, It's working fine. But when i run the same code in 4-inch the line height is not increasing based on the UIView. The lines are not working as like auto layouts.
Thanks in advance, Can anyone give your suggestion to fix this issue.

How can I mask a square image with a circle and also put a black border around the image

I have a square image 40x40 that I want to make round via clipping, but also put a black 5 pixel border around the image.
I have the following which is masking the square image so its now round
UIImage *image = self.imageView.image;
CGSize imageSize = image.size;
CGRect imageRect = CGRectMake(0, 0, imageSize.width, imageSize.height);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
// Create the clipping path and add it
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:imageRect];
[path addClip];
[image drawInRect:imageRect];
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = roundedImage;
But now I need to also add a round border around it. Do I need a new path or can I just tack onto the one one in the code above?
Add the following three lines in your code (with whatever color and stroke width you want):
CGContextSetStrokeColorWithColor(ctx, [[UIColor greenColor] CGColor]);
[path setLineWidth:50.0f];
[path stroke];
So it becomes:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create the clipping path and add it
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:imageRect];
[path addClip];
[image drawInRect:imageRect];
CGContextSetStrokeColorWithColor(ctx, [[UIColor greenColor] CGColor]);
[path setLineWidth:50.0f];
[path stroke];
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = roundedImage;

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

How can I let the user draw overlapping colors in iOS?

I am creating a drawing application like this, but I have one issue. The problem is that when I draw a line with one color and then draw a line with another color, it gives me combination of both colors where the lines intersect.
- (void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextStrokePath(context);
[super drawRect:rect];
[curImage release];
}
The rest of the project is available on GitHub.
Maybe have a look at blend modes.
https://developer.apple.com/library/mac/#documentation/graphicsimaging/Reference/CGContext/Reference/reference.html#//apple_ref/c/tdef/CGBlendMode

CoreGraphics FillPath And Stroke Path

I need to draw an hexagon and fill it with a color build with an Image as pattern.
I did:
CGContextSaveGState(context);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetFillColorWithColor(context, [[UIColor colorWithPatternImage:[UIImage imageNamed:#"patternerba.png"]] CGColor]);
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextSetLineWidth(context, 3.0);
// drawing hexagon here...
CGContextStrokePath(context);
CGContextFillPath(context);
[[NSString stringWithFormat:#"Foo"] drawAtPoint:innerRect.origin withFont:[UIFont fontWithName:#"Helvetica" size:16]];
CGContextRestoreGState(context);
But depending from the order of CGContextStrokePath and CGContextFillPath, I get an hexagon bordered but not filled or filled but not bordered. How can I fix this?
Try
CGContextDrawPath(context, kCGPathFillStroke);
Instead of
CGContextStrokePath(context);
CGContextFillPath(context);
Either use
CGContextDrawPath(context, kCGPathFillStroke);
as sch suggested, or draw the hexagon again before calling FillPath. StrokePath and FillPath remove the path that you have added to the context, thus the next call will silently fail without a path.
CGPathRef path = /* drawing hexagon here */;
CGContextAddPath(context, path);
CGContextStrokePath(context);
CGContextAddPath(context, path);
CGContextFillPath(context);
Note: the two segments of code are not equivalent and gives different result.