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;
}
Related
I need help to draw trapezoid shapes in iOS.
I am using the following code to draw the Pink shape, but it is not working:
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:CGPointMake(0, 0)];
[trianglePath addLineToPoint:CGPointMake(topView.frame.size.width, topView.frame.size.height/2)];
[trianglePath addLineToPoint:CGPointMake(100, topView.frame.size.height/2)];
CAShapeLayer *triangleMaskLayer = [CAShapeLayer layer];
[triangleMaskLayer setPath:trianglePath.CGPath];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,topView.frame.size.height-150, 200, 150)];
view.layer.mask = triangleMaskLayer;
[self.view addSubview:view];
How can I draw the pink-colored shape?
-(void)TriangularPinkView{
UIBezierPath *path = [UIBezierPath bezierPath];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 0.5;
CGPoint start = CGPointMake(CGRectGetMinX(self.pinkView.frame), CGRectGetMidY(self.pinkView.frame)+CGRectGetHeight(self.pinkView.frame)*.25);
[path moveToPoint:start];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.pinkView.frame), CGRectGetMidY(self.pinkView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetMaxX(self.pinkView.frame), CGRectGetMaxY(self.pinkView.frame))];
[path addLineToPoint:CGPointMake(CGRectGetMinX(self.pinkView.frame), CGRectGetMaxY(self.pinkView.frame))];
shapeLayer.path = [path CGPath];
// shapeLayer.fillRule = kCAFillRuleEvenOdd;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
}
I have a square UIView which i need to divide into cross section with two different colors as shown
here is my code to achieve that graph:
//Define the drawing path
UIBezierPath *path1 = [[UIBezierPath alloc] init];
//path Move to start drawing position
[path1 moveToPoint:CGPointMake(200, 100)];
//Draw a straight line from the starting position to(100, 200)
[path1 addLineToPoint:CGPointMake(100, 100)];
//To draw a line from (100, 200) to (200, 200)
[path1 addLineToPoint:CGPointMake(100, 200)];
//close path
[path1 closePath];
CAShapeLayer *layer1 = [[CAShapeLayer alloc] init];
layer1.path = path1.CGPath;
layer1.fillColor = [UIColor colorWithRed:0.88 green:0.87 blue:0.87 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer1];
UIBezierPath *path2 = [[UIBezierPath alloc] init];
[path2 moveToPoint:CGPointMake(200, 100)];
[path2 addLineToPoint:CGPointMake(200, 200)];
[path2 addLineToPoint:CGPointMake(100, 200)];
[path2 closePath];
CAShapeLayer *layer2 = [[CAShapeLayer alloc] init];
layer2.path = path2.CGPath;
layer2.fillColor = [UIColor colorWithRed:0.89 green:0.57 blue:0.53 alpha:1.0].CGColor;
[self.view.layer addSublayer:layer2];
Here is the result:
result image
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.
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;
I've been using the following code to create views with rounded corners:
- (void)setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
{
UIBezierPath* rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(_cornerRadius, _cornerRadius)];
CAShapeLayer* shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
}
So I've been calling it with something like:
[self setMaskTo:someView byRoundingCorners:UIRectCornerAllCorners];
Or:
[self setMaskTo:someOtherView byRoundingCorners:UIRectCornerBottomRight];
I now want to create some views corresponding to one of the bits on the outside of a single rounded corner...
A good approach (think I) is to create the appropriate path so that I can create a CAShapeLayer and then use that as the mask for the view (similar to above).
I'm not sure what the best approach is, which methods etc., when using the UIBezierPath class (or CGPath).
Any suggestions?
Using UIViews and a mask layer, to get the shapes that I wanted, I just needed to play around creating paths with an arc...
I'm aware that the methods for working with a CGPath can be used, but I've worked with what is available with UIBezierPath.
I've used the following methods to create the paths that I need:
- (UIBezierPath*)oppositeArcOfPathForBottomRightCorner
{
float width = _cornerRadius;
UIBezierPath* path = [UIBezierPath new];
[path moveToPoint:CGPointMake(0, width)];
[path addLineToPoint:CGPointMake(width, width)];
[path addLineToPoint:CGPointMake(width, 0)];
[path addArcWithCenter:CGPointMake(0, 0) radius:width startAngle:0 endAngle:(M_PI / 2.0f) clockwise:YES];
[path closePath];
return path;
}
- (UIBezierPath*)oppositeArcOfPathForTopLeftCorner
{
float width = _cornerRadius;
UIBezierPath* path = [UIBezierPath new];
[path moveToPoint:CGPointMake(0, width)];
[path addArcWithCenter:CGPointMake(width, width) radius:width startAngle:M_PI endAngle:(M_PI * 1.5f) clockwise:YES];
[path addLineToPoint:CGPointMake(0, 0)];
[path closePath];
return path;
}
And then something like this to use as a mask with a UIView:
- (void)setMaskTo:(UIView*)view fromPath:(UIBezierPath*)path
{
CAShapeLayer* shape = [[CAShapeLayer alloc] init];
[shape setPath:path.CGPath];
view.layer.mask = shape;
}