I am trying to draw rounded corners on rectangle in drawRect method using bezier path, but somehow the rounded corner is being shown on inner side of rectangle, instead of both inner and outer sides. Code is given below. Also attached herewith is border that is currently being drawn (outer side of border is not rounded)
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context=UIGraphicsGetCurrentContext();
//Set gray color to whole context
[[UIColor lightGrayColor] set];
CGContextSetAlpha(context,0.7);
UIRectFill(rect);
// Configure the context colors and line
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:131./255. green:148./255. blue:219./255. alpha:1.0].CGColor);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 10.0);
CGSize size=self.bounds.size;
CGFloat radius = 10.0;
CGSize guideSize=CGSizeMake(330, 130);
CGRect guideCoords= CGRectMake(size.width*.5-guideSize.width*.5, size.height*.5-guideSize.height*.5, guideSize.width , guideSize.height);
// Guide drawing
CGContextStrokeRect(context,guideCoords);
// Draw the Text
[kVinGuideMessage drawInRect:CGRectMake(guideCoords.origin.x+kSideMessageMargin, guideCoords.origin.y+guideSize.height+kMarginFromGuide, guideCoords.size.width-2*kSideMessageMargin,40) withFont:[UIFont systemFontOfSize:16.0] lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
//Get instersection and clear color of inner overlay
CGRect holeRectIntersection = CGRectIntersection(rect,guideCoords);
//----------ADDING ROUNDED CORNERS HERE-----------//
CGPathRef clippath = [UIBezierPath bezierPathWithRoundedRect:guideCoords cornerRadius:radius].CGPath;
CGContextAddPath(context, clippath);
CGContextClip(context);
//------------------------------------------------//
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
}
The outer corners are being drawn by the CGContextStrokeRect(context,guideCoords); I think. At that point you haven't set a clipping path and your line width is 10 points, so why would the outer corners be rounded? I think you'll have better luck if you set a clipping path (probably not exactly the same clipping path you've got at the bottom) before calling stroke rect on the guideCoords rectangle.
Related
I have two rectangles (two closed sub cgpaths).
Rectangle B is small and is present inside Rectangle A. All edges within it.
Is there a direct way to fill color area external to the rectangle B.
CAShapeLayer fillExternalColor something like that? If not a direct way, how to do this programmatically?
A - Purple color
B - Yellow color
So I tried drawing A and then drawing B. I wanted B to be of clear color (for now I put Yellow) but then I see purple color of A..
I found CGRectIntersection method that gives AnB and CGRectUnion method that gives AuB.
Is there a method that gives the rest of the area which is AuB - AnB?
You are using a CAShapeLayer. If your fillColor and your strokeColor are both opaque (alpha 1.0), you can simply set the layer's backgroundColor to fill those pixels that are within the layer's bounds but outside of its stroked and filled path.
My test code:
#implementation ViewController {
CAShapeLayer *layer;
}
- (void)viewDidLoad {
[super viewDidLoad];
layer = [CAShapeLayer layer];
layer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 250, 250)].CGPath;
layer.fillColor = [UIColor yellowColor].CGColor;
layer.strokeColor = [UIColor whiteColor].CGColor;
layer.lineWidth = 4;
layer.backgroundColor = [UIColor purpleColor].CGColor;
[self.view.layer addSublayer:layer];
}
- (void)viewDidLayoutSubviews {
layer.frame = self.view.bounds;
}
#end
Result:
I wanted to add red border inner rectangle on UIImage with masked outer part.
I came through this page. The following code is using CGContextEOFillPath can be helpful to others like me. (Some of the code is gathered from other pages.)
-(UIImage ) imageByDrawingBorderRectOnImage:(UIImage )image theRect:(CGRect)theRect
{
// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(image.size);
// draw original image into the context
[image drawAtPoint:CGPointZero];
// get the context for CoreGraphics
CGContextRef ctx = UIGraphicsGetCurrentContext();
// set stroking color and to draw rect
[[UIColor redColor] setStroke];
// drawing with a red stroke color
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
// the line width to 3
CGContextSetLineWidth(ctx, 3.0);
// Add Stroke Rectangle,
CGContextStrokeRect(ctx, theRect);
// Now draw fill outside part with partial alpha gray color
// drawing with a gray stroke color
CGMutablePathRef aPath = CGPathCreateMutable();
// outer rectangle
CGRect rectangle = CGRectMake( 0, 0, image.size.width, image.size.height);
CGPathAddRect(aPath, nil, rectangle);
// innter rectangle
CGPathAddRect(aPath, nil, theRect);
// set gray transparent color
CGContextSetFillColorWithColor(ctx, [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:0.5].CGColor);
// add the path to Context
CGContextAddPath(ctx, aPath);
// This method uses Even-Odd Method to draw in outer rectangle
CGContextEOFillPath(ctx);
// make image out of bitmap context
UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();
// free the context
UIGraphicsEndImageContext();
return retImage;
}
Regards.
Assuming A is the bigger shape, B is the smaller, inner shape, and bounds refers to the containing rect of A (probably the bounds of the view)
Clip shape B to the context (-addClip should do it)
CGContextClearRect the bounds
Fill shape A
Edit, found the source of this code
Given HoleView : UIView you must set:
self.opaque = NO;
self.backgroudColor = [UIColor clearColor];
and in drawRect:
[[UIColor purpleColor] setFill];
UIRectFill(A);
CGRect gapRectIntersection = CGRectIntersection(B, A);
[[UIColor clearColor] setFill];
UIRectFill(gapRectIntersection);
kCAFillRuleEvenOdd
Specifies the even-odd winding rule. Count the total number of path crossings. If the number of crossings is even, the point is outside the path. If the number of crossings is odd, the point is inside the path and the region containing it should be filled.
Available in OS X v10.6 and later.
Declared in CAShapeLayer.h.
Refer to :CAShapeLayer Class reference
I'm trying to draw a rectangle, which should have black color border of width 5.0, I am getting the rectangle as seen below,
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextStrokePath(context);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.5);
CGContextFillRect(context, rect);
I can make it clear / transparent (white) background instead the green one showing right now with [UIColor whiteColor].CGColor but then it should have black border also.
How do I set the customized border to rectangle?
Set the stroke color and width as desired, for example:
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 5.0f);
CGContextStrokeRect(context, rect);
If you are also filling the rectangle, do this after filling so the fill doesn't cover up the stroke.
I have to draw many shapes like rectangle, circle, triangle etc.I am drawing them trough core graphics.
It is working fine.
I want to ask suppose I am having an image (square image of say 1024*1024), and now I want my circle to draw as image means like I draw red color circle or other color, so if it is possible to show my image as drawn in the circle, like the image is circle,
My code for normal circle drawing:-
- (void)drawRect:(CGRect)rect{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [ [UIColor colorWithRed:255.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:1] CGColor]);
CGContextSetAlpha(ctx, 0.7);
CGContextMoveToPoint(ctx, radius, radius);
CGContextAddArc(ctx, radius,radius, radius, radians(0), radians(360), 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
}
I want to draw my image as circle.
Basically I want like we can fill colors in core graphics drawing whether circle, arc, triangle. so is that possible to fill my shape with my image instead of any solid colors.
Is this possible and if yes please suggest me how to achieve this.
Thanks in advance.
try this out for setting color in CGContextSetFillColorWithColor function [[UIColor alloc]initWithPatternImage:[UIImage imageNamed:#"pattern.jpg"]CGColor];
Add a UIView with and rectangular on the image.
In this view, you must draw the hole.
Now i not have the mac and i cannot check, but try to substitute
CGContextSetFillColorWithColor(ctx, [ [UIColor colorWithRed:255.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:1] CGColor]);
with
CGContextSetBlendMode(currentContext, kCGBlendModeClear);
let me know
I am trying to draw my grouped table cells in the drawRect method. I get the following results, but I have one problem with. I want the outer border to be a darker, but I can not seem to accomplish this, which I am sure is a problem with my drawing.
I like the color of the line in the middle between the cells, just not the outer border of the cells.
Edit:
-(void)drawRect:(CGRect)rect
{
const float kLineWidth = 3.0;
UIColor *topLineColor = [UIColor whiteColor];
UIColor *bottomLineColor = [UIColor colorWithRed:225.0f/255.0f green:225.0f/255.0f blue:225.0f/255.0f alpha:1.0f];
UIColor *backgroundColor = [UIColor colorWithRed:242.0f/255.0f green:242.0f/255.0f blue:242.0f/255.0f alpha:1.0f];
CGColorRef bottomSeparatorColorRef = [bottomLineColor CGColor];
CGColorRef topSeparatorColorRef = [topLineColor CGColor];
CGContextRef context = UIGraphicsGetCurrentContext();
UIRectCorner corners = 0;
switch(self.position) {
case OTCellBackgroundViewPositionTop:
corners = UIRectCornerTopLeft | UIRectCornerTopRight;
break;
case OTCellBackgroundViewPositionMiddle:
break;
case OTCellBackgroundViewPositionBottom:
corners = UIRectCornerBottomLeft | UIRectCornerBottomRight;
break;
default:
break;
}
[backgroundColor setFill];
[topLineColor setStroke];
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:CGSizeMake(10.0f, 10.0f)];
[bezierPath fill];
[bezierPath stroke];
[bezierPath setLineWidth:3.0f];
if (self.position == OTCellBackgroundViewPositionTop) {
// Draw the Bottom Line
CGContextSetStrokeColorWithColor(context, bottomSeparatorColorRef);
CGContextSetLineWidth(context, kLineWidth);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextMoveToPoint(context, 0.0, rect.size.height);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
CGContextStrokePath(context);
}
if (self.position == OTCellBackgroundViewPositionBottom) {
// Draw the Top Line
CGContextSetStrokeColorWithColor(context, topSeparatorColorRef);
CGContextSetLineWidth(context, kLineWidth);
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextMoveToPoint(context, 0.0, 0.0);
CGContextAddLineToPoint(context, rect.size.width, 0);
CGContextStrokePath(context);
}
}
You are setting the top separator to white.
UIColor *topLineColor = [UIColor whiteColor];
CGColorRef topSeparatorColorRef = [topLineColor CGColor];
// Top Line
CGContextSetStrokeColorWithColor(context, topSeparatorColorRef);
Simply set it to a darker color.
Let's look at the code for the top position cell. First, you create a path that represents an outline of the whole cell. Next, you fill the background - good. Then you stroke the two sides and top - good. Then you stroke the bottom of the cell - good. Then you add and stroke the full outline path you created before doing the other parts - bad.
Get rid of the path you create and don't stroke that path. Your code for the background, top line, and bottom line are all you need.
The extra stroke you do last is redrawing the full cell outline in the last color you used which was for the bottom line. This is covering your top line stroke.
On a side note, you should use an if-else setup:
if (_position == OTCellBackgroundViewPositionTop) {
// draw top cell
} else if (_position == OTCellBackgroundViewPositionMiddle) {
// draw middle cell
} else if (_position == OTCellBackgroundViewPositionBottom) {
// draw bottom cell
)
This sort of structure should always be used when you only need one possible path to execute. The structure you had is appropriate when it is possible or desired for multiple paths to be executed.
I'm thinking something like this might be more manageable. You'll have to tweak the bezierPath sizes etc to get the right.
UIRectCorner corners = 0;
switch(position) {
case OTCellBackgroundViewPositionTop:
corners = UIRectCornerTopLeft | UIRectCornerTopRight;
break;
case OTCellBackgroundViewPositionMiddle:
break;
case OTCellBackgroundViewPositionBottom:
corners = UIRectCornerBottomLeft | UIRectCornerBottomRight;
break;
}
[backgroundColor setFill];
[topLineColor setStroke];
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect
byRoundingCorners:corners
cornerRadii:CGSizeMake(3.f, 3.f)];
[bezierPath fill];
[bezierPath stroke];
// Now stroke over the lines in a different colour.
Edit
Looking at the code you have posted.
You have set the top line colour to white - hence it is white, maybe you meant to set it to the gray colour you require.
The outlines being drawn are being clipped. To solve this you could inset the rect by half the width of the lines you are drawing.
rect = CGRectInsetRect(rect, 0.5f * kLineWidth, 0.5f * kLineWidth);
You need to set the stroke width before you stroke the line or it will use the default
[bezierPath setLineWidth:kLineWidth];
[bezierPath stroke];
trying to draw circle divided to dynamically provided number of sectors. In the end my circle should look like pie.
I've created class Circle which contains number of Pies inside. Circle has method - (void)draw which calles [pie draw]; in for (Pie *pie in self.pies) loop.
Implementation of pie looks like this:
- (void)draw {
CGContextRef context = UIGraphicsGetCurrentContext();
float startAngleRads = degreesToRadians(_startAngle);
float endAngleRads = degreesToRadians(_endAngle);
CGContextBeginPath(context);
CGContextSetLineWidth(context, 1.0f);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGColorRef strokeColor = [_strokeColor CGColor];
CGContextSetStrokeColorWithColor(context, strokeColor);
CGColorRef fillColor = [_bgColor CGColor];
CGContextSetFillColorWithColor(context, fillColor);
CGContextMoveToPoint(context, _x, _y);
CGContextAddArc(context, _x, _y, _r, startAngleRads, endAngleRads, YES);
CGContextDrawPath(context, kCGPathStroke);
CGContextFlush(context);
}
This draws nice circle with sectors but without any filling of course. When I change last lines to CGContextDrawPath(context, kCGPathStrokeFill); my stroke lines disappears and only last line (last sector) stays at the screen, other parts of circle are filled with bgcolor and no stroke is visible anymore.
The question is: how can I draw completly separated "sectors" (every sector should look like triangle with Arc and Stroke and Fill). I need this because I want to toggle visibility of that sectors but at the moment I cant even figure out how to draw them correctly.
If this is important, all drawing happens on the layer with self.opaque = NO;.
Ok, found my error: had to set NO in CGContextAddArc call.