Rikh Rikh - 2 months ago 17
iOS Question

Drawing bezierPath

I was tinkering around with BezierPath and noticed something that I can't seem to figure out. This is the code-

UIBezierPath *path = [UIBezierPath new];

CGSize screenDimensions = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

CGPoint firstPoint = CGPointMake(screenDimensions.width/2, screenDimensions.height/2);
CGPoint secondPoint = CGPointMake(screenDimensions.width/2 + 10, screenDimensions.height/2 + 10);
CGPoint thirdPoint = CGPointMake(screenDimensions.width/2 - 10, screenDimensions.height/2 + 10);

[path moveToPoint:firstPoint];
[path addLineToPoint:secondPoint];
[path addLineToPoint:thirdPoint];
[path addLineToPoint:firstPoint];

[path closePath];

CAShapeLayer *tempLayer = [CAShapeLayer new];
[tempLayer setPath:path.CGPath];

UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(screenDimensions.width/2 - 30, screenDimensions.height/2 - 30, 100, 100)];

// UIView *tempView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

[tempView setBackgroundColor:[UIColor blueColor]];
tempView.layer.mask = tempLayer;
[self.view addSubview:tempView];


If i run the above code block, nothing is drawn on the UIView that is added on the screen. But if i were to comment the current "tempView" and uncomment the currently commented allocation, it would draw on screen perfectly. Can anyone please point out what am I doing wrong here when setting the frame or is it something else?

Answer

It's a simple problem.

Let's say the screen dimensions are 320x480 (and old iPhone). This means that firstPoint will be 160, 240.

In the current code, your view's frame is 130, 210, 100, 100. It's width and height are both 100.

The shape layer will be drawn relative to the view's bounds, not its frame. So as far as the layer and bezier path are concerned, the view's bounds are 0, 0, 100, 100. Since firstPoint is outside those bounds, it doesn't appear. It's actually drawn but outside the visible bounds of the view.

When you switch the two lines that create the view, the view's frame becomes 0, 0, 320, 480. This means its bounds is also 0, 0, 320, 480. The view is much larger now and the layer and bezier path fit and can be seen.

The proper solution is to create the coordinates of the bezier path based on the size of the view it will be applied to, not the size of the screen. This way, the bezier path will fit inside its view no matter how big it is.

More like this:

CGSize screenDimensions = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(screenDimensions.width/2 - 30, screenDimensions.height/2 - 30, 100, 100)];

//    UIView *tempView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

UIBezierPath *path = [UIBezierPath new];

CGPoint firstPoint = CGPointMake(tempView.bounds.size.width/2, tempView.bounds.size.height/2);
CGPoint secondPoint = CGPointMake(tempView.bounds.size.width/2 + 10, tempView.bounds.size.height/2 + 10);
CGPoint thirdPoint = CGPointMake(tempView.bounds.size.width/2 - 10, tempView.bounds.size.height/2 + 10);

[path moveToPoint:firstPoint];
[path addLineToPoint:secondPoint];
[path addLineToPoint:thirdPoint];
[path addLineToPoint:firstPoint];

[path closePath];

CAShapeLayer *tempLayer = [CAShapeLayer new];
[tempLayer setPath:path.CGPath];

[tempView setBackgroundColor:[UIColor blueColor]];
tempView.layer.mask = tempLayer;
[self.view addSubview:tempView];