I have a UIViewController which has a UIView in it and I want to draw a straight dotted line on it. What is the easiest and performant way to do this? How do I do this? It will just be a straight horizontal dotted line of width 150 with gray color. I've looked around and it seems that using
CGContextSetLineDash is the solution and here's what I have so far:
-(void) drawRect:(CGRect) rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 100);
CGFloat dashes[] = {1,1};
CGContextSetLineDash(context, 2.0, dashes, 2);
CGContextStrokePath(context);
}
CGContextStrokePath draws the current path, however, you never add any path to your context, so nothing is drawn.
Add the following two lines before your CGContextStrokePath call and you should see something:
CGContextMoveToPoint(context, 0, self.bounds.size.height * 0.5);
CGContextAddLineToPoint(context, self.bounds.size.width, self.bounds.size.height * 0.5);
If you haven't already set your stroke color, you should also add something like this (50% gray):
CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
I'm not sure if the result is really what you want, a 100 point dotted line with a pattern of {1, 1} will look more like an rectangle with a pinstripe pattern than like a dotted line. If you want your dots to be circles, you will have to draw those manually in some sort of loop.
Try this:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, 2.0);
CGFloat lengths[] = {0, 8};
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineDash(context, 0.0f, lengths, 2);
CGContextMoveToPoint(context, 10, 10);
CGContextAddLineToPoint(context, 200, 10);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
Related
Here is a picture of two lines drawn in a UITableViewCell with the same function, and same width, and color
As you can see the bottom line is a lot thicker than the other line.
The code I am using for drawing:
[CSDrawing drawLineWithColor:[UIColor blackColor] width:1.0 yPosition:1.0 rect:rect];
[CSDrawing drawLineWithColor:[UIColor blackColor] width:1.0 yPosition:CGRectGetMaxY(rect) - 3.0 rect:rect]; // draw a line on top and bottom
+(void)drawLineWithColor:(UIColor *)color width:(CGFloat)width yPosition:(CGFloat)yPosition rect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextMoveToPoint(context, 0.0, yPosition);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), yPosition);
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, width);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
The problem was with the backgroundView being stretched to fit the content of the cell when the cell was being reused. When the cell was bigger the pixels were stretched. This is solved be setting the contentMode property to UIViewContentModeRedraw
I have the touchesBegan void before this which triggers this event,
but i need this line to show, wait for so many seconds, then disappear:
- (void)drawRect:(CGRect)rect {
// Drawing code
//Make a simple rectangle and fill background BLUE with half Opeque
CGContextRef context = UIGraphicsGetCurrentContext();
//[[UIColor blueColor] set];
//CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
//rect = CGRectMake(20, 20, 40, 40);
//CGContextFillRect(context, rect);
//Make a simple RED line from 0,0 to 100, 100 in a FRAME
//CGContextSetRGBFillColor(context, 100.0, 0.0, 0.0, 1.0);
[[UIColor redColor] set];
CGContextMoveToPoint(context, _spaceShip.center.x, _spaceShip.center.y);
CGContextAddLineToPoint( context, nextLocX, nextLocY);
CODE FOR MAKING THE LINE DISAPPEAR
}
Redraw the frame without that line would be the obvious solution.
Draw over it in the background color would be a less-pretty solution that might in some cases run faster.
I like to draw a glass with a few Elements
- Top Ellipse
- Bottom Ellipse
- and the Lines Inbetween
Next, it should be filled with a Gradient. The Elements work, but at the point, where the middle of the glass comes in touch with the top or bottom ellipse the area get's clipped.
- (void)drawRect:(CGRect)rect
{
CGPoint c = self.center;
// Drawing code
CGContextRef cx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(cx, 1.0);
[[UIColor whiteColor] setStroke];
// DrawTheShapeOfTheGlass
CGContextBeginPath(cx);
// Top and Bottom Ellipse
CGContextAddEllipseInRect(cx, CGRectMake(0, 0, 100, 20));
CGContextAddEllipseInRect(cx, CGRectMake(10, 90, 80, 20));
// Define the points for the Area inbetween
CGPoint points[] = { {0.0,10.0},{10.0,100.0},{90.0,100.0},{100.0,10.0} };
CGContextAddLines(cx, points, 4);
CGContextClosePath(cx);
// Clip, that's only the Clipped-Area wil be filled with the Gradient
CGContextClip(cx);
// CreateAndDraw the Gradient
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat colorSpace[] = {1.0f, 1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f };
CGFloat locations[] = { 0.0, 1.0 };
CGGradientRef myGradient = CGGradientCreateWithColorComponents(rgbColorSpace, colorSpace, locations, 2);
CGPoint s = CGPointMake(0, 0);
CGPoint e = CGPointMake(100, 100);
CGContextDrawLinearGradient(cx, myGradient, s, e, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGColorSpaceRelease(rgbColorSpace);
CGGradientRelease(myGradient);
}
Here how it looks like:
Is there any possibility to "fill" the whole ellipse? I played around with BlendModes but it didn't help.
Thanks
Try replacing the points[] initialization code with the following...
CGPoint points[] = {{0.0,10.0},{100.0,10.0},{90.0,100.0},{10.0,100.0}};
CoreGraphics uses the non-zero winding count rule to determine how to fill a path. Since ellipses are drawn clockwise and your trapezoid was drawn counter clockwise, the overlapping regions were not filled. Changing the drawing order of the trapezoid to clockwise will result in an object that is completely filled.
I'm trying to draw a simple grid pattern on a black background using Core Graphics. The gridlines will be green. I am currently creating and drawing in an image context, then using the resulting image to pattern the background of my view:
CGFloat gridSize = 45;
UIGraphicsBeginImageContext(CGSizeMake(gridSize, gridSize));
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(ctx);
// Create black background fill.
CGContextSetFillColorWithColor(ctx, [[UIColor colorWithRed:0.0
green:0.0
blue:0.0
alpha:1.0] CGColor]);
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, gridSize, 0);
CGContextAddLineToPoint(ctx, gridSize, gridSize);
CGContextAddLineToPoint(ctx, 0, gridSize);
CGContextAddLineToPoint(ctx, 0, 0);
CGContextFillPath(ctx);
// Set context variables for line drawing.
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
CGContextSetStrokeColorWithColor(ctx, [[UIColor colorWithRed:0.0
green:1.0
blue:0.0
alpha:1.0] CGColor]);
CGContextSetLineWidth(ctx, 1);
// Draw top and bottom grid lines.
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, gridSize, 0);
CGContextMoveToPoint(ctx, gridSize, gridSize);
CGContextAddLineToPoint(ctx, 0, gridSize);
CGContextStrokePath(ctx);
// Draw left and right grid lines.
CGContextMoveToPoint(ctx, gridSize, 0);
CGContextAddLineToPoint(ctx, gridSize, gridSize);
CGContextMoveToPoint(ctx, 0, gridSize);
CGContextAddLineToPoint(ctx, 0, 0);
CGContextStrokePath(ctx);
// Draw a "cross" in the center of the image to troubleshoot blending.
CGContextMoveToPoint(ctx, 20, 20);
CGContextAddLineToPoint(ctx, 40, 20);
CGContextStrokePath(ctx);
CGContextMoveToPoint(ctx, 30, 10);
CGContextAddLineToPoint(ctx, 30, 30);
CGContextStrokePath(ctx);
UIGraphicsPopContext();
UIImage *gridImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Set background color to a pattern based on the drawn image.
[self setBackgroundColor:[[UIColor alloc] initWithPatternImage:gridImage]];
However, this code results in the following:
Note that there are brighter areas that occur at the intersection of any lines. The crosses that are somewhat randomly placed within the grid pattern were put there just to test whether the bright areas still occur when not affected by the edges of the patterning (they do).
It is these bright areas at the line intersections that I wish to alleviate. To make sure I hadn't accidentally fooled myself using some sort of optical illusion, I checked the pixel colors in the middle of the lines as well as at their intersections.
Pixel values at midpoint of green line:
R: 0
G: 129
B: 0
Pixel values at intersection of two green lines:
R: 0
G: 191
B: 0
I have checked the Apple Core Graphics docs regarding blending modes, and ascertained that the default blending mode is kCGBlendModeNormal, which should, when painting colors with alpha = 1, should "completely obscure the background", and any previously painted colors. Though this is the default blending mode, I still set it explicitly in the above code, and yet I still see these bright squares.
What I expect instead is to see the lines of a uniform green color, presumably with the RGB profile:
R: 0
G: 255
B: 0
What am I missing?
It looks as if the lines are drawn with an alpha of 50% but double the specified line width. This happens if you have a line width of 1 pixel but draw horizontal or vertical lines using integer coordinates.
Your coordinates specify an infinitely thin line from the start to the end coordinates. The drawn line should then extend to both sides of the thin line by half the stroke width. In your case, this means the line would need to cover half a pixel to the left and to the right or to the top and to the bottom of grid. Since only full pixels can be drawn, the alpha is reduced to 50% and the full pixel drawn instead.
The solution is simple: Add 0.5 to all your coordinates.
I am using the code below and am trying everything to color the resulting circle that it draws, but cannot for the life of me figure it out! Can anyone help? How do I color the circle in that my method draws?
What I have so far is this:
-(void)drawCircleAtPoint:(CGPoint)p withRadius:(CGFloat)radius inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, p.x, p.y, radius, 0, 2*M_PI, YES);
CGContextStrokePath(context);
UIGraphicsPopContext();
}
- (void)drawRect:(CGRect)rect
{
CGPoint midPoint;
midPoint.x = self.bounds.origin.x + self.bounds.size.width/2;
midPoint.y = self.bounds.origin.y + self.bounds.size.width/2;
CGFloat size = self.bounds.size.width/2;
if (self.bounds.size.height < self.bounds.size.width) size = self.bounds.size.height/2;
size *= 0.90;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
[[UIColor blackColor] setStroke];
CGColorRef color = [[UIColor redColor] CGColor];
CGContextSetFillColorWithColor(context, color);
CGContextFillPath(context);
[self drawCircleAtPoint:midPoint withRadius:size inContext:context];
}
You're trying to fill the current path, but you haven't added anything to it yet. The only point at which you add anything to the current path is in drawCircleAtPoint:withRadius:inContext:, after which you only stroke it.
Move your CGContextFillPath call into that method. You'll want to fill before you stroke, since the stroke will reset the current path. (If you want to fill on top of the inside of the stroke, you'll need to save the gstate before stroking and restore it after, so that the current path is still set when you fill.)