uibezier path - will not display - ios

I am trying to use UIbezierPaths for the first time and I am having no success in displaying it in the view. I am using a very old version of xcode (3.2.6).
-(void)drawshape:(CGRect)Rect {
UIBezierPath *cloudpath = [UIBezierPath bezierPath];
[cloudpath moveToPoint:CGPointMake(100.0, 100.0)];
[cloudpath addLineToPoint:CGPointMake(200, 200)];
[cloudpath addLineToPoint:CGPointMake(200, 300)];
[cloudpath addLineToPoint:CGPointMake(250, 330)];
[cloudpath addLineToPoint:CGPointMake(20, 400)];
[cloudpath closePath];
cloudpath.lineWidth = 2;
[[UIColor blueColor]setStroke];
[cloudpath stroke];
}
I have also Imported QuartzCore. I have only added -(void)drawshape in viewcontroller.h
When I build, i have no errors.Any help is massively welcomed

You will need to initiate the drawing from overriding drawRect: in a custom UIView and not in your view controller.

Related

CAShapeLayer mask doesn't show up

I'm making mask using UIBezierPath and CAShapeLayer with this code:
- (void)createPath {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(0, 0)];
[path addLineToPoint:CGPointMake(100, 100)];
[path moveToPoint:CGPointMake(100, 100)];
[path addLineToPoint:CGPointMake(0, 100)];
[path moveToPoint:CGPointMake(0, 100)];
[path addLineToPoint:CGPointMake(0, 0)];
[path closePath];
CAShapeLayer *layer = [CAShapeLayer new];
layer.frame = self.contentView.bounds;
layer.path = path.CGPath;
self.contentView.layer.mask = layer;
}
But instead of masking my contentView disappears completely. I tried to look at path in debugger and it looks exactly as I want it to look.
When using the layer.mask, the first is to get the right path. You don't need to move to a new point every time. By that way, your path is made of three or four subpaths which can not be closed to form a right path.
The second is trying to use in the View class itself, not to call for other subviews, like contentView. Because you may not know when to call it in subviews. Run the following in a UIView subclass, like in a UITableViewCell (awake from nib). You can get what I mean. If you really want to use contentView, just find the right position to put your layer code. like override setNeedLayout, etc.
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self createPath];
}
- (void)createPath {
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(0, 0)];
[path addLineToPoint:CGPointMake(100, 100)];
// [path moveToPoint:CGPointMake(100, 100)];
[path addLineToPoint:CGPointMake(0, 100)];
// [path moveToPoint:CGPointMake(0, 100)];
[path addLineToPoint:CGPointMake(0, 0)];
[path closePath];
CAShapeLayer *layer = [CAShapeLayer new];
layer.frame = self.contentView.bounds;
layer.path = path.CGPath;
self.layer.mask = layer; // not self.contentView.layer.mask;
}

How to create tableview with curved frame?

Does anybody know how to create an UITableView with a curved frame, like MacOS downloads (in Dock panel) on iOS?
I tried to use for this the UIBezierPath class, but unfortunally I didn't succeed. For example I did this:
_tableView = [[TVCurveTableView alloc] initWithFrame:CGRectMake(10, self.view.frame.size.height - 130, 70, 160)];
UIBezierPath *bezierPath = [[UIBezierPath alloc]init];
[bezierPath moveToPoint:CGPointMake(10, self.view.frame.size.height - 10)];
[bezierPath addLineToPoint:CGPointMake(40, (self.view.frame.size.height-10) - 160)];
[bezierPath addLineToPoint:CGPointMake(110, (self.view.frame.size.height-10) - 160)];
[bezierPath addLineToPoint:CGPointMake(80, (self.view.frame.size.height-10))];
[bezierPath addLineToPoint:CGPointMake(10, (self.view.frame.size.height-10))];
[bezierPath closePath];
bezierPath.lineWidth = 2;
CAShapeLayer *shapeView = [[CAShapeLayer alloc] init];
[shapeView setPath:bezierPath.CGPath];
shapeView.strokeColor = [UIColor redColor].CGColor;
[_tableView.layer addSublayer:shapeView];
Maybe you have some ideas?
My COBezierTableView does something similar though not with the tilting of the cells. That would be a nice thing to have as a option though, so maybe I´ll look into it. Fell tree also to deliver a pullrequest yourself if you find a sollution. ;-)
https://github.com/knutigro/COBezierTableView

Creating a UIBezierPath in UIView Category. not being shown

I am trying to create a triangle using UIBezierPath in a category of UIView. but the triangle is not being shown. also getting an : CGContextSetFillColorWithColor. So my question is how to make triangle or any path using a category of UIView. Demo Project
#import "UIView+Bubble.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIView (Bubble)
+(UIView *)makeBubble{
UIView *customView = [[UIView alloc] init];
customView.frame=CGRectMake(0, 0, 320, 500);
UIBezierPath *triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointMake(100, 0)];
[triangle addLineToPoint:CGPointMake(0, 100)];
[triangle addLineToPoint:CGPointMake(200, 100)];
[triangle closePath];
[[UIColor blackColor] setFill];
[triangle fill];
customView.layer.shadowPath = [triangle CGPath];
return customView;
}
#end
In ViewController.m using it like:-
- (void)viewDidLoad
{
UIView *helpBubble=[UIView makeBubble];
[self.view addSubview:helpBubble];
}
In your UIView+Bubble.h category UIBezierPath tries to draw triangle on a null context. If you want to draw shape using UIBezierPath like above, you have to put this code inside drawRectmethod of a View class.
On the other hand, you could create a new context to draw. You may modify your makeBubble method as follow:
+(UIView *)makeBubble{
// declare UIimageView, not UIView
UIImageView *customView = [[UIImageView alloc] init];
customView.frame=CGRectMake(0, 0, 320, 500);
// create a new contex to draw
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0);
UIBezierPath *triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointMake(100, 0)];
[triangle addLineToPoint:CGPointMake(0, 100)];
[triangle addLineToPoint:CGPointMake(200, 100)];
[triangle closePath];
[[UIColor blackColor] setFill];
[triangle fill];
customView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return customView;
}
EDIT:
to make it dynamic you could pass a cgRect argument, like
+(UIView *)makeBubble:(CGRect)rect
also change to customView.frame=rect; and UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0); inside this method. And call makeBubble:(CGRect)rect method as
UIView *helpBubble=[UIView makeBubble:/*your desire rect*/];
P.S. it will be great if you calculate the points depending on the rect too.

Crash using [UIBezierPath CGPath] with CAShapeLayer under ARC

I'm getting a BAD ACCESS error using [UIBezierPath CGPath] with CAShapeLayer under ARC. I've tried bridging in various ways but I'm not clear if that is the problem. I have isolated the crash to using the result of the makeToPath method:
maskLayer = [CAShapeLayer layer];
maskLayer.path = [self makeToPath];
But this doesn't crash:
maskLayer = [CAShapeLayer layer];
maskLayer.path = [self makeFromPath];
Is there something invalid with the path created by makeToPath? I'm planning to use the from and to paths with a CABasicAnimation once I sort this crash out. What is the correct ARC bridging for CGPathRefs from UIBezierPath?
-(CGPathRef)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
return [triangle CGPath];
}
-(CGPathRef)makeFromPath
{
UIBezierPath*rect = [UIBezierPath bezierPathWithRect:self.view.frame];
return [rect CGPath];
}
UPDATE So I changed my .h file per an answer below but I am still getting the crash
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
-(CGPathRef)makeFromPath CF_RETURNS_RETAINED;
I also tried making my methods return a UIBezierPath instance per the answer here (shown below). Still no success. Anyone want to give me the longform explanation on how to fix this?
maskLayer.path = [[self makeToPath] CGPath];// CRASHES
morph.toValue = CFBridgingRelease([[self makeToPath] CGPath]);// CRASHES
-(UIBezierPath*)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
return triangle;
}
The problem is with returning the CGPath. The value returned is a CGPathRef which is not covered by ARC. The UIBezierPath you create is released after the method ends. Thus also freeing the CGPathRef.
You can specify a source annotation to let ARC know your intent:
In the .h file:
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
-(CGPathRef)makeFromPath CF_RETURNS_RETAINED;
As the other poster pointed out, you are returning a CGPath reference taken from a UIBezierPath object that goes out of scope at the end of the method. As the docs on the UIBezierPath CGPath property say:
The path object itself is owned by the UIBezierPath object and is
valid only until you make further modifications to the path.
You need to create a copy of your CGPath and return that:
-(CGPathRef)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
CGPathRef theCGPath = [triangle CGPath];
return CGPathCreateCopy(theCGPath);
}
The way I read the link to the llvm project, I think that the cf_returns_retained qualifier is intended to tell the caller the memory management policy for the returned value, rather than doing the retain for you.
Thus I think you would both need to create a copy of the path AND add the cf_returns_retained qualifier. I'm not clear on the syntax of that qualifier, however. (Never used it before.)
Assuming the other poster had the right syntax, it would look something like this:
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
CGPathRef theCGPath = [triangle CGPath];
return CGPathCreateCopy(theCGPath);
}

Unexpected LineJoinStyle behavior when lines in path at 180 degrees

I'm getting a clipped LineJoin in a UIBezierPath when one line comes back exactly over the previous line. If I adjust the second line by one pixel, the LineJoin behaves as expected. Here's the code:
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:10.0f];
[path setLineCapStyle:kCGLineCapRound];
[path setLineJoinStyle:kCGLineJoinRound];
[path moveToPoint:CGPointMake(100, 100)];
[path addLineToPoint:CGPointMake(200, 100)];
[path addLineToPoint:CGPointMake(150, 100)];
[path moveToPoint:CGPointMake(100, 120)];
[path addLineToPoint:CGPointMake(200, 120)];
[path addLineToPoint:CGPointMake(150, 121)];
[[UIColor redColor] setStroke];
[path stroke];
Here's what's displayed:
Is this a bug?
If not, is there some way to get the top path LineJoin to be rounded? (without fudging the points)
This came up when I made a UIBezierPath from 'touch-input', and while scribbling around sometimes this happened.
This is fixed in iOS 7.
Open Radar also updated.

Resources