Setting mask layer on UITableViewCell's subview overrides Auto Layout constraints - ios

I have a UITableViewCell with multiple subviews. One of the subviews is a UILabel and the cell's height is dynamically sized based on the amount of text in the UILabel. This works perfectly.
I have another subview in the cell that has constraints as well. This subview is always supposed to have the exact same height as the cell. This works perfectly as well.
However, I run into problems when trying to set a mask layer on that subview. The mask layer works correctly, but then the subview's height is wrong and it is not the same height as the cell.
Here is my mask layer code:
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.mySubview.bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight)
cornerRadii:CGSizeMake(10, 10)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.mySubview.bounds;
maskLayer.path = maskPath.CGPath;
self.mySubview.layer.mask = maskLayer;
I have been doing research and trying to find a way to fix this so I can both set the mask layer and have the subview have it's correct height but I haven't been able to get it to work.
I have seen this solution recommended several times now:
[self setNeedLayout];
[self layoutIfNeeded];
// Customize cell after here
But this doesn't work for me either. Is there a way for me to know when the Auto Layout constraints have been applied so that I can then apply the mask layer afterwards?
The mask layer code is really simple, it uses the bounds of the subview, and the bounds are off because it's using the bounds that exist before the constraints have been applied and the subview has the correct height. At least I think I'm understanding that correctly.

I finally got it. I'm not sure if this is the correct place to put this or if it might cause performance problems, but so far it works perfectly:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.mySubview.bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight)
cornerRadii:CGSizeMake(10, 10)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = self.mySubview.bounds;
maskLayer.path = maskPath.CGPath;
self.mySubview.layer.mask = maskLayer;
}
I had to override drawRect: in my UITableViewCell subclass and set the mask layer there.

I have had same problem and doing things in - (void)drawRect:(CGRect)rect does the work but it could be costly in terms of performance.
You can call your clipping or shadow methods in perform selector
[self performSelector:#selector(<your drawing method>) withObject:nil afterDelay:0.0000001 ];//a very low delay

Related

How to curve UIVew only top corner and not whole view in Objective C?

I am new in iOS and I am facing problem regarding to curve UIView. I want to curve the radius of the top of UIView like this in the Image
As you can see the screenshot of my work view.
I am using code like this
UIBezierPath *maskPath = [UIBezierPath
bezierPathWithRoundedRect:ViewSwapMyWork.bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(70, 70)
];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = ViewSwapMyWork.bounds;
maskLayer.path = maskPath.CGPath;
ViewSwapMyWork.layer.mask = maskLayer;
First your view should have the same height and width means it should be square, then you can do like this,
[ViewSwapMyWork.layer setCornerRadius:ViewSwapMyWork.frame.size.width/2];
[ViewSwapMyWork.layer setMasksToBounds:YES];

Rounded Corners only for the bottoms edges of UITableView

I'm using the below code to make rounded corners only for the bottom edges of tableView
CALayer *capa = self.patientTableView.layer;
//Round
CGRect bounds = capa.bounds;
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight)
cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
[capa addSublayer:maskLayer];
capa.mask = maskLayer;
This code works fine, but the tableview is not showing up the contents below its frame height (but it scrolls to its offset.y).
You can fix this by putting the table view inside a UIView, and then apply the mask to that container view. That way the mask will not move with the contentOffset of the table view.

rounded corner uilabel not visible (xcode 4.5.2)

I am new to IOS development, try to create top rounded corner label
by following link
How do I round only the top two corners of a UILabel?
But after applying the mask, the whole label cannot be seen, Any clue?
Here is my code.
#synthesize title;
- (void)viewDidLoad
{
[super viewDidLoad];
title.layer.borderColor=[[UIColor blueColor]CGColor];
title.layer.borderWidth=2;
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:title.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(10.0f, 10.0f)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame=title.bounds;
maskLayer.path = maskPath.CGPath;
title.layer.mask = maskLayer;
}
EDITED
Tried the suggestion to create the label in program, the layout become
https://docs.google.com/file/d/0B60xg2ZCEjOqeTBEWG92N0NodFU/edit?usp=sharing
The corner disappear and I still want to set the mask the "title" labal?
EDITED
Finally give up, for others benefit,I wrap the label in uiview , map the uiview to a class (i.e. Myview.m), and put the same code in method "- (void)drawRect:(CGRect)rect{}" in "Myview.m". The display showed as what I want!.
I'm not sure if this is your problem because you didn't show how the title label is created, but if you're creating it in code, you need to be sure to alloc/init the label, as well as give it a frame and then add it as a subview of its superview.
title = [[UILabel alloc] initWithFrame:CGRectMake(100.0f, 100.0f, 60.0f, 30.0f)];
title.layer.borderColor=[[UIColor blueColor]CGColor];
title.layer.borderWidth=2;
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:title.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(10.0f, 10.0f)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame=title.bounds;
maskLayer.path = maskPath.CGPath;
title.layer.mask = maskLayer;
[self.view addSubview:title];
first of all my advice is don't use "title" as a UILabel name because all UIViewController has a property that name is title.
After changing label name and sure IBOutlet is connected add this code:
lblTitle.layer.masksToBounds = YES;
I just figure out if you create a label on storyboard you dont need to alloc again. I wrote this code and it works;
_L_corner.layer.borderColor =[[UIColor blueColor] CGColor];
_L_corner.layer.borderWidth = 5.0f;
_L_corner.layer.cornerRadius = 3.0f;
Finally give up, for others benefit, and used another work around:-
1) wrap the label in uiview ,
2) map the uiview to a class (i.e. Myview.m),
3) put the same code in method
- (void)drawRect:(CGRect)rect{
title.layer.borderColor=[[UIColor blueColor]CGColor];
title.layer.borderWidth=2;
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:title.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(10.0f, 10.0f)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame=title.bounds;
maskLayer.path = maskPath.CGPath;
title.layer.mask = maskLayer;
}
in "Myview.m".
The display showed as what I want!

Adding Rounded Corners to UIView without breaking interactions.

This answer works great, Adding Rounded Corners to only top of UITableView? except my UIBarButtonItems are no longer clickable. My guess is that the mask is now sitting on top of the buttons breaking the interaction.
Does anyone have any ideas to implement this without interfering with the rest of the view?
Have you tried just masking your tableView's layer:
CAShapeLayer * maskLayer = [CAShapeLayer layer];
maskLayer.path = [UIBezierPath bezierPathWithRoundedRect: self.bounds byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii: (CGSize){10.0, 10.}].CGPath;
self.tableView.layer.mask = maskLayer;
or just using:
self.tableView.layer.cornerRadius = 10.0
for the whole table

Keeping CAShapeLayer Mask Static During Animation

I'm trying to rotate a UIImageView within a circular mask (which is set with myImageView.layer.mask). The problem is that any time I attempt to rotate said UIImageView, the mask rotates with it. Here is some code.
Setting up the mask:
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, - 169)
radius:191
startAngle:0.0
endAngle:2*M_PI
clockwise:YES];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setFrame:myImageView.bounds];
[shapeLayer setPath:[path CGPath]];
myImageView.layer.mask = shapeLayer;
Animation:
[UIView animateWithDuration:kRotationTime animations:^(void){
myImageView.transform = CGAffineTransformMakeRotation(angle);
}];
And that's basically all there is to it. A UIImageView rotating about its own center within a fixed-position circular mask--that's the desired effect. Perhaps there is another way to structure the view hierarchy so that myImageView and the mask are siblings, but I haven't had luck going that route.
Put the image view into an additional plain UIView superview. Set the layer mask on the superview. Animate the image view.

Resources