create a non-rectangular UIView - iphone

I need to create a view (a uibutton) of strange shape.
Is this possible with quartz2d? i used this code for buil my UIView subclass
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillPath(context);
}
but this is a draw inside a standard UIView (rectangular UIView)

Related

How to set UILabel non rectangular frame

Im trying to make a UILabel with the edges looking like the following image.
Here is the drawRect: from my UILabel subclass.
-(void)drawRect:(CGRect)rect{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGRect labelRect = self.bounds;
CGPoint bottomPoint = CGPointMake(labelRect.size.width, rect.size.height);
CGPoint topMinus30Point =CGPointMake(labelRect.size.width-30, 0);
CGPoint topPoint = CGPointMake(labelRect.size.width, 0);
CGContextBeginPath (context);
//from bottom to -30 top
CGContextMoveToPoint(context, bottomPoint.x,bottomPoint.y);
CGContextAddLineToPoint(context, topMinus30Point.x,topMinus30Point.y);
//from -30 to top
CGContextMoveToPoint(context, topMinus30Point.x,topMinus30Point.y);
CGContextAddLineToPoint(context, topPoint.x,topPoint.y);
//from top to bottom
CGContextMoveToPoint(context, topPoint.x,topPoint.y);
CGContextAddLineToPoint(context, bottomPoint.x,bottomPoint.y);
CGContextClosePath(context);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
How do I crop the created path from the current frame ?
[Im just getting started with Core Graphics, so please be gentle :)]
Any pointers on how to achieve this would be really helpful.
Thanks
Try this:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// clear drawing rect
CGContextClearRect(context, rect);
// save 1
CGContextSaveGState(context);
CGRect labelRect = self.bounds;
CGPoint bottomPoint = CGPointMake(labelRect.size.width, rect.size.height);
CGPoint topMinus30Point = CGPointMake(labelRect.size.width-30, 0);
CGPoint topPoint = CGPointMake(labelRect.size.width, 0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0f, 0.0f);
CGContextAddLineToPoint(context, topMinus30Point.x, topMinus30Point.y);
CGContextAddLineToPoint(context, bottomPoint.x, bottomPoint.y);
CGContextAddLineToPoint(context, 0.0f, bottomPoint.y);
CGContextAddLineToPoint(context, 0.0f, 0.0f);
CGContextClosePath(context);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextDrawPath(context, kCGPathFill);
// restore 1
CGContextRestoreGState(context);
}
Put this in the init you use:
[self setBackgroundColor:[UIColor clearColor]];
One approach is,
set the background color of label to clear color, and draw the required shape inside your drawRect method using CGContext.
Your drawRect will become like this
- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect labelRect = self.bounds;
CGPoint bottomPoint = CGPointMake(labelRect.size.width, rect.size.height);
CGPoint topMinus30Point =CGPointMake(labelRect.size.width-30, 0);
//from bottom to -30 top
CGContextMoveToPoint(context, self.bounds.origin.x,self.bounds.origin.y);
CGContextAddLineToPoint(context, topMinus30Point.x,topMinus30Point.y);
CGContextAddLineToPoint(context, bottomPoint.x,bottomPoint.y);
CGContextAddLineToPoint(context, self.bounds.origin.x,self.bounds.origin.x + self.bounds.size.height);
CGContextAddLineToPoint(context, self.bounds.origin.x,self.bounds.origin.y);
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGContextFillPath(context);
}
Another approach is using the CGContextClip using this approach your drawRect will become like this
CGContextMoveToPoint(context, self.bounds.origin.x,self.bounds.origin.y);
CGContextAddLineToPoint(context, topMinus30Point.x,topMinus30Point.y);
CGContextAddLineToPoint(context, bottomPoint.x,bottomPoint.y);
CGContextAddLineToPoint(context, self.bounds.origin.x,self.bounds.origin.x + self.bounds.size.height);
CGContextAddLineToPoint(context, self.bounds.origin.x,self.bounds.origin.y);
CGContextClip(context);
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGContextFillRect(context, self.bounds);
Hope this helps

How can i call this method in self.view?

I am making this method for drawing line now what I want is to call it in another methods how can I do that, please help me out of this that how can I add this in self.view?
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGFloat dashArray[] = {2,6,4,2};
CGContextSetLineDash(context, 3, dashArray, 4);
CGContextMoveToPoint(context, 10, 200);
CGContextAddQuadCurveToPoint(context, 150, 10, 300, 200);
CGContextStrokePath(context);
}
Mark the view as needing a redraw:
[self.view setNeedsDisplay];
See reference.
[self.view setNeedsDisplay];
This will call your draw rect method.

How can i draw a semicircle using CoreGraphics

I am trying to draw a semicircle using Core Graphics and Filling it with some color.I want to replace color with image by using CALayer. Can any one help how to do this Thanks!
Code goes here.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 0, 500);
CGContextAddArc(context, 60, 500, 50, 90, 180, 0);
CGContextStrokePath(context);
You need to specify the angles in radians, not degrees. 180 degrees = π radians. So in your example:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 10, 500);
CGContextAddArc(context, 60, 500, 50, M_PI / 2, M_PI, 0);
CGContextStrokePath(context);
Note that I also moved the starting point (…MoveToPoint) 10 pixels to the right, because that’s where the arc begins.
The given answers are not working on iOS 7 for me!
I created a little category to create a circle with the angle of a percentage.
Maybe you wanna check it out.You can still adopt the methode if you only want to create a semicircle.
Here is the: GitHub Link
And that is what its look like:
CGPoint circleCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x, circleCenter.y, 50, 90, 180, 0);
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y);
CGContextSetFillColorWithColor(context, [UIColor colorWithPatternImage:[UIImage imageNamed:#"add-icon.png"]].CGColor);
CGContextFillPath(context);
CGContextAddArc(context, circleCenter.x, circleCenter.y, 50, 180, 90, 0);
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y);
CGContextSetFillColorWithColor(context, [UIColor colorWithPatternImage:[UIImage imageNamed:#"appIcon_58.png"]].CGColor);
CGContextFillPath(context);
What you need, which I found the other day, is a great tool that lets you visualise Core Graphics code - after drawing it in a graphics program.
Its called Paint Code.
PaintCode

CoreGraphics taking a while to show on a large view - can i get it to repeat pixels?

This is my coregraphics code:
void drawTopPaperBackground(CGContextRef context, CGRect rect) {
CGRect paper3 = CGRectMake(10, 14, 300, rect.size.height - 14);
CGRect paper2 = CGRectMake(13, 12, 294, rect.size.height - 12);
CGRect paper1 = CGRectMake(16, 10, 288, rect.size.height - 10);
//Shadow
CGContextSetShadowWithColor(context, CGSizeMake(0,0), 10, [[UIColor colorWithWhite:0 alpha:0.5]CGColor]);
CGPathRef path = createRoundedRectForRect(paper3, 0);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextFillPath(context);
//Layers of paper
CGContextSaveGState(context);
drawPaper(context, paper3);
drawPaper(context, paper2);
drawPaper(context, paper1);
CGContextRestoreGState(context);
}
void drawPaper(CGContextRef context, CGRect rect) {
//Shadow
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0,0), 1, [[UIColor colorWithWhite:0 alpha:0.5]CGColor]);
CGPathRef path = createRoundedRectForRect(rect, 0);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextRestoreGState(context);
//Gradient
CGContextSaveGState(context);
CGColorRef startColor = [UIColor colorWithWhite:0.92 alpha:1.0].CGColor;
CGColorRef endColor = [UIColor colorWithWhite:0.94 alpha:1.0].CGColor;
CGRect firstHalf = CGRectMake(rect.origin.x,
rect.origin.y, rect.size.width / 2, rect.size.height);
CGRect secondHalf = CGRectMake(rect.origin.x + (rect.size.width / 2),
rect.origin.y, rect.size.width / 2, rect.size.height);
drawVerticalGradient(context, firstHalf, startColor, endColor);
drawVerticalGradient(context, secondHalf, endColor, startColor);
CGContextRestoreGState(context);
CGContextSaveGState(context);
CGRect redRect = rectForRectWithInset(rect, -1);
CGMutablePathRef redPath = createRoundedRectForRect(redRect, 0);
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextAddPath(context, redPath);
CGContextSetShadowWithColor(context, CGSizeMake(0, 0), 15.0, [[UIColor colorWithWhite:0 alpha:0.1] CGColor]);
CGContextStrokePath(context);
CGContextRestoreGState(context);
}
The view is a UIScrollView, which contains a textview. Every time the user types something and goes onto a new line, I call [self setNeedsDisplay]; and it redraws the code. But when the view starts to get long - around 1000 height, it has very noticeable lag. How can i make this code more efficient? Can i take a line of pixels and make it just repeat that, or stretch it, all the way down?
You can draw your repeating background once, into an offscreen context, pull out the image from it, then create a UIColor with the pattern image and set that as your background colour. The image will then be tiled for you.
You start an image context with UIGraphicsBeginImageContextWithOptions(). The options include the size of your expected image - I assume this is the width of your scrollview and x pixels high, the opacity, and scale. Send 0 for the scale for automatic retina support.
You can then act as if you were within a drawRect method - so your functions above can be called as normal.
Then, extract the image:
UIImage *background = UIGraphicsGetImageFromCurrentImageContext();
End the image context:
UIGraphicsEndImageContext();
Then create the colour:
UIColor *backgroundColor = [UIColor colorWithPatternImage:background];
And set that as the background for your scrollview. Typed on a phone, so apologies for ... everything.

How to draw a concentric circle in iphone?

I want to draw a ring. Ring should filled in a outer circle. I referred a documentation http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html#//apple_ref/doc/uid/TP30001066-CH211-TPXREF101. But still had problem to get the outcome. Here is the code.
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextClearRect(ctx, rect);
CGContextSetRGBFillColor(ctx, 0.0, 255.0, 1.0, 1.0);CGContextFillPath(ctx);
CGContextStrokeEllipseInRect(ctx, CGRectMake(125, 125, 150, 150));
CGContextBeginPath(ctx);
CGContextEOFillPath(ctx);
CGContextFillEllipseInRect(ctx, CGRectMake(100, 100, 200, 200));
You need something more like this:
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, rect);
CGContextAddEllipseInRect(ctx,
CGRectMake(
rect.origin.x + 10,
rect.origin.y + 10,
rect.size.width - 20,
rect.size.height - 20));
CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
CGContextEOFillPath(ctx);
}
This will add two ellipses to your current path (one being smaller than the other, but centered around the same point). EOFillPath will essentially "subtract" the inner ellipse from the outer ellipse when it fills the path.
To create "concentric" circles, if that's really what you wanted, you can simply repeat this for more - continually smaller - ellipses.