How to get CAShapeLayer's frame confront to its superview? - ios

Can anybody help me to get frame of CAShapeLayer which is been added in UIImageView as a SubLayer?
Following is my code for the same:
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.15].CGColor;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.lineWidth = 3.0;
shapeLayer.zPosition = 1;
[_imgBackground.layer insertSublayer:shapeLayer atIndex:1];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(50, 50)]; // left top point of rack
[path addLineToPoint:CGPointMake(100, 50)]; // right top point of rack
[path addLineToPoint:CGPointMake(100, 100)]; // right bottom point of rack
[path addLineToPoint:CGPointMake(50, 100)]; // left bottom point of rack
[path closePath]; // closing rectangle/path
shapeLayer.path = path.CGPath;
As I know we can get frame from the following line:
CGRect bounds = CGPathGetBoundingBox(shapeLayer.path);
But it only returns frame according to self.view
I want its frame according to UIImageView.
Thanks in advance.

Well I got the answer from James's comment. Following line saved my day:
CGRect bounds = [self.view convertRect:CGPathGetBoundingBox(shapeLayer.path) toView:_imgBackground];
from this reference.

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;
}

Bottom Corner Radius and shadow only at bottom ofUIView in Objective C

I want to add radius to bottom left and bottom right corners of an UIView and then drop shadow only at bottom of the same UIView.
I have gone through solutions in which all corners are provided with radius and then shadow. That is working fine. But when I use UIBeizerPath to add radius to bottom corners the shadow property doesn't seem to work.
I am using Objective-C and XCode 8.1.
How can I do it?
Using below code bottom corners get their radius but shadow properties doesn't work.
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 40)];
[testView setBackgroundColor:[UIColor yellowColor]];
// shadow
testView.layer.shadowColor = [UIColor colorWithRed:156.0f/255.0f green:153.0f/255.0f blue:153.0f/255.0f alpha:1.0f].CGColor;
testView.layer.shadowOffset = CGSizeMake(0.0f, 2.0f);
testView.layer.shadowRadius = 4.0f;
testView.layer.shadowOpacity = 0.5f;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0, 0.0)];
[path addLineToPoint:CGPointMake(0.0, CGRectGetHeight(testView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetWidth(testView.frame), CGRectGetHeight(testView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetWidth(testView.frame), 0.0)];
testView.layer.shadowPath = path.CGPath;
//bottom corners radius
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:testView.bounds
byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight)
cornerRadii:CGSizeMake(2.0, 2.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.view.bounds;
maskLayer.path = maskPath.CGPath;
testView.layer.mask = maskLayer;
The mask is masking the shadow. You need to have two view one inside the other. Apply the mask to the inner view and the shadow to the outer view.

Bezierpath with rounded corners

I am using the following code to show the pointer like triangle view as shown in image below.
UIView *triangleView = [[UIView alloc] initWithFrame:CGRectMake(70.0f,58.0f, self->_createAccountView.frame.size.width ,20.0f)];
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:CGPointMake(0, 0)];
[trianglePath addLineToPoint:CGPointMake((self->_createAccountView.frame.size.width/7) -8, (self->_createAccountView.frame.size.height/4))];
[trianglePath addLineToPoint:CGPointMake((self->_createAccountView.frame.size.width/5) , 0)];
[trianglePath closePath];
trianglePath.lineJoinStyle = kCGLineJoinRound;
CAShapeLayer *triangleMaskLayer = [CAShapeLayer layer];
[triangleMaskLayer setPath:trianglePath.CGPath];
triangleView.backgroundColor = [UIColor colorWithRed:1.00 green:1.00 blue:1.00 alpha:1.0];
triangleView.layer.mask = triangleMaskLayer;
[self->_AccountView addSubview:triangleView];
This works fine but I want the pointing edge of the triangle view to be rounded. How can make it rounded? Any help is appreciated!
Change the lineJoin to kCALineJoinRound.
triangleMaskLayer.lineJoin = kCALineJoinRound;

How to fix invalid context 0x0 with UIBezierPath?

I am trying to find the best way to implement an rounded rectangle (e.g. looling like the iphone icons). My search suggested using UIBezierPath.
In order to test that class I made a new xcode template (single view application) and basically just added the following lines in ViewController's viewDidLoad:
UIBezierPath* path = [UIBezierPath
bezierPathWithRoundedRect: CGRectMake(10, 10, 120, 120)
cornerRadius: 5];
[[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0] setFill];
[path stroke];
[path fill];
Now I get several "...invalid context 0x0 error...". I assume that I have to set a context first?! But how do I do this or if not fix those errors otherwise?
My search on that error came up with a few posts. Unfortunaltely all of them seemed to have rather complex coding associated. I'm pretty sure however that I have just a very basic misunderstanding here.
Thank you!
you can use this and assign that in layer of your view
UIBezierPath *maskpath=[UIBezierPath bezierPathWithRoundedRect:view1.bounds
byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight
cornerRadii:CGSizeMake(10.0,10.0)];
CAShapeLayer *maskLayer=[CAShapeLayer layer];
maskLayer.frame=view1.bounds;
maskLayer.path=maskpath.CGPath;
[view1.layer addSublayer:maskLayer];
in case it is helpful for someone else: on basis of the code provided by johnykumar and another post on a similar topic:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
CGRect frame = CGRectMake(50.0, 50.0, 150.0, 150.0);
CGFloat radius = 20.0;
UIView *frontView = [[UIView alloc] initWithFrame:frame];
frontView.backgroundColor = [UIColor redColor];
CAShapeLayer * maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:frontView.bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(radius, radius)].CGPath;
frontView.layer.mask = maskLayer;
[self.view addSubview:frontView];
}

BezierPath and masking

I want to set up UIBezierPath as mask into my view:
The goal is something like this:
So i draw the View with frame:
CGFloat round = 80;
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width/2-105, 0, 210, 60+round)];
myView.backgroundColor = [UIColor redColor];
And then try to add BezierMask:
UIBezierPath *aPath = [UIBezierPath bezierPath];
CGSize viewSize = CGSizeMake(myView.frame.size.width, myView.frame.size.height); //(210,80)
CGPoint startPoint = CGPointMake(myView.frame.origin.x,myView.frame.origin.y); //(279,0)
[aPath moveToPoint:startPoint]; //(279,0)
[aPath addLineToPoint:CGPointMake(startPoint.x+viewSize.width,startPoint.y)]; //(489,0)
[aPath addLineToPoint:CGPointMake(startPoint.x+viewSize.width,startPoint.y+viewSize.height-round)]; //(489,60)
[aPath addQuadCurveToPoint:CGPointMake(startPoint.x,startPoint.y+viewSize.height-round) controlPoint:CGPointMake(startPoint.x+(viewSize.width/2),80)]; //(279,60) : (384,80)
[aPath closePath];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = myView.bounds;
layer.path = aPath.CGPath;
myView.layer.mask = layer;
[self addSubview:myView];
But my view is disappearing after that. Why?
I guess you are using improper coordinations for your mask layer. Your mask layer must be positioned within the view which it masks, not in the view's superview.
Try these changes:
CGSize viewSize = myView.bounds.size;
CGPoint startPoint = CGPointZero;
Your code with those little modifications works OK for me.

Resources