Setting mask layer on UITableViewCell's subvie

2020-05-24 16:42发布

问题:

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.

回答1:

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.



回答2:

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