I wanted to draw a vertical single bar graph. I was trying to do it using DrawRect, but could not able to do so. Can nay one hlep me to knwo if this can be done easily by providing start and end point in view to change the color.
thanks
If you have a custom view, it's just a matter of drawing the lines and rectangles that you want. For example:
- (void)drawRect:(CGRect)rect
{
CGAffineTransform t = CGAffineTransformMakeScale(1, -1);
self.transform = t;
CGFloat baseline = 50;
CGFloat inset = 40;
CGFloat barWidth = 20;
CGFloat barHeight = 80;
CGRect r = CGRectMake(inset + barWidth, baseline, barWidth, barHeight);
UIBezierPath *p = [UIBezierPath bezierPathWithRect:r];
[[UIColor redColor] set];
[p fill];
p = [UIBezierPath bezierPath];
[p moveToPoint:CGPointMake(inset, baseline)];
[p addLineToPoint:CGPointMake(inset + 3 * barWidth, baseline)];
[[UIColor blackColor] set];
[p stroke];
}
produces this:
I've created a UIView subclass with the -drawRect: method above and created an instance of that view that's the size of the window. Note that I flipped the coordinate system using a transform -- you don't have to do that, but drawing with the origin at the lower left corner can be easier.
try this one
1. http://www.raywenderlich.com/13271/how-to-draw-graphs-with-core-plot-part-2
2 OVGraph.- a library for the graphs
Related
I have to draw an oval shape button, i don't want to set the image in oval shape.
I have read that you can draw different shaper with UIBezierPath but i am unable to draw a proper oval shape.
Here is the code is am using to create a circular shape.
self.layer.borderWidth=1.0;
self.clipsToBounds = YES;
[self setTitleColor:ktextColor forState:UIControlStateNormal];
self.layer.cornerRadius = self.bounds.size.width/2;//half of the width
self.layer.borderColor=[[UIColor whiteColor]CGColor];
Any help is appreciated !!
You can set the delegate for your button's layer and implement the delegate method `displayLayer:'
-(void)displayLayer:(CALayer *)layer
{
UIGraphicsBeginImageContext(layer.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, CGRectGetWidth(layer.frame), CGRectGetHeight(layer.frame))];
[[UIColor whiteColor] setFill];
[ovalPath fill];
[[UIColor blackColor] setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
UIImage *imageBuffer = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
layer.contents = (id)[imageBuffer CGImage];
}
You can also create a CAShapelayer and than add gesture to the layer as below:
-(void)generateOvalWithSize:(CGSize)size origin:(CGPoint)origin {
CAShapeLayer ovalLayer = [CAShapeLayer layer];
CGMutablePathRef ovalPath = CGPathCreateMutable();
CGPathAddEllipseInRect(ovalPath, NULL, CGRectMake(origin.x, origin.y, size.width, size.height));
CGPathCloseSubpath(ovalPath);
ovalLayer.path = ovalPath;
// Configure the apperence of the circle
ovalLayer.fillColor = [UIColor whiteColor].CGColor;
ovalLayer.strokeColor = [UIColor whiteColor].CGColor;
ovalLayer.lineWidth = 2;
// Add to parent layer
[[self layer] addSublayer:ovalLayer];
}
i have been using these two functions for a while, i haven't come across any issues yet, but if someone sees an issue please let me know.
you can pass anything that is a subclass of UIView (ie. UIButton, UICollectionViewCell, etc.)
+ (void)setCornerRadius:(CGFloat)radius forView:(UIView*)view
{
[view.layer setCornerRadius:radius];
[view.layer setMasksToBounds:YES];
}
+ (void)setBordersForView:(UIView*)view width:(CGFloat)width color:(UIColor*)color
{
view.layer.borderColor = color.CGColor;
view.layer.borderWidth = width;
}
the above yields me the effect below in a collection view:
the collection view cell has a single button which is bound all the way around the edges (auto layout) and takes up the full height and width of the cell.
then i pass in the entire cell (or self.viewForBaseLineLayout if calling from within the cell) as the view parameter in both functions listed above.
for the radius parameter i am passing 20.0f.
(but this value will vary depending on the size the view you are passing; you just have to play around with it)
i know this post is old, but maybe it will help someone new : )
You can use the OBShapedButton class Download Here
I know that it is possible to add a transparent/translucent overlay view on a UIImagePickerController by using the drawrect method and by adjusting the alpha value of a CGRect UIColor for example. But is it possible to get a blurry effect instead of the translucent one ? I hope I am clear enough...
Thanks !
EDIT (add code)
- (void)drawRect:(CGRect)rect{
CGFloat toolbarSize = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 0 : 80;
CGFloat width = CGRectGetWidth(self.frame);
CGFloat height = CGRectGetHeight(self.frame) - toolbarSize;
CGFloat heightSpan = floor(height / 2 - self.cropSize.height / 2);
CGFloat widthSpan = floor(width / 2 - self.cropSize.width / 2);
//fill outer rect
[[UIColor colorWithRed:0. green:0. blue:0. alpha:0.5] set];
UIRectFill(self.bounds);
//fill inner border
[[UIColor colorWithRed:1. green:1. blue:1. alpha:0.5] set];
UIRectFrame(CGRectMake(widthSpan - 1, heightSpan - 1, self.cropSize.width + 2, self.cropSize.height + 2));
//fill inner rect
[[UIColor clearColor] set];
UIRectFill(CGRectMake(widthSpan, heightSpan, self.cropSize.width, self.cropSize.height));
}
}
I used this framework to achieve a blurry view, worked really well for me
FXBlurView
I'm creating a simple app where when the user presses a button, a series of lines will be drawn on the screen and the user will be able to see these lines drawn in real time (almost like an animation).
My code looks something like this (has been simplified):
UIGraphicsBeginImageContext(CGSizeMake(300,300));
CGContextRef context = UIGraphicsGetCurrentContext();
for (int i = 0; i < 100; i++ ) {
CGContextMoveToPoint(context, i, i);
CGContextAddLineToPoint(context, i+20, i+20);
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextStrokePath(context);
}
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
My problem is that:
1) As soon as the user presses the button, the UIThread blocks until the drawing is done.
2) I can't get the lines to be drawn on the screen one at a time - I've tried setting the UIImage directly inside the loop and also tried setting a layer content inside the loop.
How do I get around these problems?
You say "just like an animation". Why not do an actual animation, a la Core Graphics' CABasicAnimation? Do you really need to show it as a series of lines, or is a proper animation ok?
If you want to animate the actual drawing of the line, you could do something like:
#import <QuartzCore/QuartzCore.h>
- (void)drawBezierAnimate:(BOOL)animate
{
UIBezierPath *bezierPath = [self bezierPath];
CAShapeLayer *bezier = [[CAShapeLayer alloc] init];
bezier.path = bezierPath.CGPath;
bezier.strokeColor = [UIColor blueColor].CGColor;
bezier.fillColor = [UIColor clearColor].CGColor;
bezier.lineWidth = 5.0;
bezier.strokeStart = 0.0;
bezier.strokeEnd = 1.0;
[self.view.layer addSublayer:bezier];
if (animate)
{
CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animateStrokeEnd.duration = 10.0;
animateStrokeEnd.fromValue = [NSNumber numberWithFloat:0.0f];
animateStrokeEnd.toValue = [NSNumber numberWithFloat:1.0f];
[bezier addAnimation:animateStrokeEnd forKey:#"strokeEndAnimation"];
}
}
Then all you have to do is create the UIBezierPath for your line, e.g.:
- (UIBezierPath *)bezierPath
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0, 0.0)];
[path addLineToPoint:CGPointMake(200.0, 200.0)];
return path;
}
If you want, you can patch a bunch of lines together into a single path, e.g. here is a roughly sine curve shaped series of lines:
- (UIBezierPath *)bezierPath
{
UIBezierPath *path = [UIBezierPath bezierPath];
CGPoint point = self.view.center;
[path moveToPoint:CGPointMake(0, self.view.frame.size.height / 2.0)];
for (CGFloat f = 0.0; f < M_PI * 2; f += 0.75)
{
point = CGPointMake(f / (M_PI * 2) * self.view.frame.size.width, sinf(f) * 200.0 + self.view.frame.size.height / 2.0);
[path addLineToPoint:point];
}
return path;
}
And these don't block the main thread.
By the way, you'll obviously have to add the CoreGraphics.framework to your target's Build Settings under Link Binary With Libraries.
I have this picture, represented in red on the following image. I am trying to create this "hairlines" on the corners of the picture. When printed, the lines are intended to have 1 point of width and 15 points of length.
this is the code I am using...
1) the first thing I do is to create a context that is 60 points larger horizontally and vertically, so I can draw the black lines.
CGFloat newWidth = 60.0f + redImage.size.width;
CGFloat newHeight = 60.0f + redImage.size.height;
UIGraphicsBeginImageContextWithOptions(CGSizeMake( newWidth, newHeight),
YES,
[redImage scale]);
Then, I define the lines start...
NSArray *startOfPoints = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(15, 0)],
[NSValue valueWithCGPoint:CGPointMake(15 + redImage.size.width, 0.0f)],
[NSValue valueWithCGPoint:CGPointMake(15, 15 + redImage.size.height)],
[NSValue valueWithCGPoint:CGPointMake(15 + redImage.size.width, 15 + redImage.size.height)],
[NSValue valueWithCGPoint:CGPointMake(0, 15)],
[NSValue valueWithCGPoint:CGPointMake(15 + redImage.size.width,15)],
[NSValue valueWithCGPoint:CGPointMake(0, 15 + redImage.size.height)],
[NSValue valueWithCGPoint:CGPointMake(15 + redImage.size.width,
15 + redImage.size.height)],
nil];
// these points define, in order, the start of each of the four vertical line and the start of each of the horizontal lines
Then, I draw the lines
CGContextRef c = UIGraphicsGetCurrentContext();
// go to the beginning of each vertical line and draw the line down
for (int i=0; i<4; i++) {
CGPoint aPoint = [[startOfPoints objectAtIndex:i] CGPointValue];
CGContextBeginPath(c);
CGContextSetStrokeColorWithColor(c, [UIColor blackColor].CGColor);
CGContextSetLineWidth(c, 1.0f);
CGContextMoveToPoint(c, aPoint.x, aPoint.y);
CGContextAddLineToPoint(c, aPoint.x, aPoint.y + 15.0f);
CGContextStrokePath(c);
}
// go to the beginning of each horizontal line and draw the line right
for (int i=5; i<9; i++) {
CGPoint aPoint = [[startOfPoints objectAtIndex:i] CGPointValue];
CGContextBeginPath(c);
CGContextSetStrokeColorWithColor(c, [UIColor blackColor].CGColor);
CGContextSetLineWidth(c, 1.0f);
CGContextMoveToPoint(c, aPoint.x, aPoint.y);
CGContextAddLineToPoint(c, aPoint.x + 15.0f, aPoint.y );
CGContextStrokePath(c);
}
but I end with a huge black square...
what am I missing?
NOTE: this code doesn't show the red image being drawn, this because I want to get the lines right. I am obtaining a huge black square, instead of the lines. The huge square has the size of the context and is the same I would obtain if I simply create the context and fill it with black... :(
When you create a bitmap graphics context using UIGraphicsBeginImageContextWithOptions, every pixel in the bitmap is initialized to all zeros, which is black (if you set opaque to YES, which you did) or transparent (if you set opaque to NO).
You can fill the bitmap with white before drawing anything else by doing this right after UIGraphicsBeginImageContextWithOptions returns:
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0, newWidth, newHeight));
I'm making some custom control. One of the subviews of the control is transparent UIView with UIBezierPath path drawn on. On the one of the photos there is just let's say border of the UIBezierPath (there's called [path stroke]), but on the second one you can see what happens when I call [path fill]. I'd like the path filled to create shape similar to the one on the first photo. drawRect method from this transparent UIView is below.
- (void)drawRect:(CGRect)rect
{
// Drawing code
[super drawRect:rect];
UIBezierPath *path;
[[UIColor greenColor] setStroke];
[[UIColor greenColor] setFill];
//Angles
CGFloat startAngle = degreesToRadians(225);
CGFloat endAngle = degreesToRadians(315);
CGPoint center = CGPointMake(CGRectGetMidX(rect), lRadius);
path = [UIBezierPath bezierPathWithArcCenter: center radius:lRadius startAngle:startAngle endAngle:endAngle clockwise:YES];
rightEndOfLine = path.currentPoint;
bigArcHeight = rightEndOfLine.y;
CGFloat smallArcHeight = lRadius - bigArcHeight - sRadius;
CGFloat smallArcWidthSquare = (8*smallArcHeight*sRadius) - (4 * (smallArcHeight * smallArcHeight));
smallArcWidth = sqrtf(smallArcWidthSquare);
leftStartOfLine = CGPointMake((rect.size.width - smallArcWidth)/2, lRadius-sRadius + smallArcHeight);
CGFloat lengthOfSpace = (rect.size.width - rightEndOfLine.x);
[path moveToPoint:leftStartOfLine];
[path addArcWithCenter:center radius:sRadius startAngle:startAngle endAngle:endAngle clockwise:YES];
rightStartOfLine = path.currentPoint;
leftEndOfLine = CGPointMake(lengthOfSpace, bigArcHeight);
[path moveToPoint:rightStartOfLine];
[path addLineToPoint:rightEndOfLine];
[path moveToPoint:leftStartOfLine];
[path addLineToPoint:leftEndOfLine];
[path closePath];
[path stroke];
// [path fill];
}
Thanks for help !
Try to remove all of your moveToPoint calls. This is a continuous shape so they are not required, and they are confusing the filling algorithm. You can start at the top left corner, draw the arc clockwise, draw the segment (?) line, draw the arc anticlockwise, then draw the last segment line (or close the path). This will fill properly.