jj0b
jj0b

Reputation: 1126

UICollectionViewCell with rounded corners AND drop shadow not working

I want my UICollectionViewCells to have rounded corners and drop shadows but I have run into a problem where it seems I can only have one or the other, but not both.

To just round the corners I use this code in the initialization of the cell:

CALayer *layer = [self layer];
[layer setCornerRadius:4];
[layer setRasterizationScale:[[UIScreen mainScreen] scale]];
[layer setShouldRasterize:YES];

To just add a drop shadow I use this code in the initialization of the cell:

CALayer *layer = [self layer];
[layer setMasksToBounds:NO];
[layer setRasterizationScale:[[UIScreen mainScreen] scale]];
[layer setShouldRasterize:YES];
[layer setShadowColor:[[UIColor blackColor] CGColor]];
[layer setShadowOffset:CGSizeMake(0.0f,0.5f)];
[layer setShadowRadius:8.0f];
[layer setShadowOpacity:0.2f];
[layer setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:layer.cornerRadius] CGPath]];

To try and have rounded corners and a drop shadow I use this code in the initialization of the cell:

CALayer *layer = [self layer];
[layer setMasksToBounds:NO];
[layer setCornerRadius:4];
[layer setRasterizationScale:[[UIScreen mainScreen] scale]];
[layer setShouldRasterize:YES];
[layer setShadowColor:[[UIColor blackColor] CGColor]];
[layer setShadowOffset:CGSizeMake(0.0f,0.5f)];
[layer setShadowRadius:8.0f];
[layer setShadowOpacity:0.2f];
[layer setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:layer.cornerRadius] CGPath]];

but this results in the drop shadow only.

Is this a bug or am I doing something wrong?

Upvotes: 20

Views: 33065

Answers (5)

Dennis
Dennis

Reputation: 2221

I think I ran into a similar issue. My problem was that clipping in my subviews of the UICollectionViewCell didn't work properly with shadows and rounded borders. The exact same code worked just fine before when I had that view (as a standard UIView subclass though) in a UIScrollView.

So long story short, I moved all this setup from the initWithCoder to a later place after getting it from -dequeueReusableCellWithReuseIdentifier:forIndexPath:. Solved the problem for me. Seems like UICollectionViews are doing something I wouldn't expect to their cells' layers at some point?

Upvotes: 2

Lal Krishna
Lal Krishna

Reputation: 16180

If you place all your subviews into the UICollectionViewCell content view, which you probably are, you can set the shadow on the cell's layer and the border on the contentView's layer to achieve both results.

cell.contentView.layer.cornerRadius = 2.0f;
cell.contentView.layer.borderWidth = 1.0f;
cell.contentView.layer.borderColor = [UIColor clearColor].CGColor;
cell.contentView.layer.masksToBounds = YES;

cell.layer.shadowColor = [UIColor lightGrayColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0f);
cell.layer.shadowRadius = 2.0f;
cell.layer.shadowOpacity = 1.0f;
cell.layer.masksToBounds = NO;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:cell.contentView.layer.cornerRadius].CGPath;

Swift 4.0

cell.contentView.layer.cornerRadius = 2.0
cell.contentView.layer.borderWidth = 1.0
cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true
cell.layer.shadowColor = UIColor.lightGray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 2.0
cell.layer.shadowOpacity = 1.0
cell.layer.masksToBounds = false
cell.layer.shadowPath = UIBezierPath(roundedRect: cell.bounds, cornerRadius: cell.contentView.layer.cornerRadius).cgPath

Upvotes: 24

Yung Dai
Yung Dai

Reputation: 159

If you are using a subclass to make the collection just make sure you do the following.

CALayer *layer = [self layer];
[layer setCornerRadius:_cornerRadius];
[layer setRasterizationScale:[[UIScreen mainScreen] scale]];
[layer setShouldRasterize:YES];
[layer setShadowColor:[[UIColor blackColor] CGColor]];
[layer setShadowOffset:CGSizeMake(0.0,4.0)];
[layer setShadowRadius:6.0f];
[layer setShadowOpacity:0.25];
[layer setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:layer.cornerRadius] CGPath]];

self.contentView.layer.cornerRadius = _cornerRadius;
self.contentView.layer.borderWidth= _borderWidth;
self.contentView.layer.borderColor = _borderColor.CGColor;
self.contentView.backgroundColor = [UIColor whiteColor];
self.backgroundColor = [UIColor clearColor];

works like a charm.

Upvotes: 0

Vov4yk
Vov4yk

Reputation: 1080

There is tricky moment. Cutting corners and dropping shadow is mutually exclusive function in one layer. Dropping shadow is frame extension process, but corners is the process of masking to bounds.

Solution is in function separation. I recommend setup shadow for the cell layer, but cut corners for contentView layer of that cell.

Upvotes: 2

Henadzi Rabkin
Henadzi Rabkin

Reputation: 7062

Works for me great:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        ...
        cell.layer.masksToBounds = YES;
        cell.layer.cornerRadius = 6;
        ...
        return cell;
    }

Upvotes: 31

Related Questions