为UICollectionViewCell添加圆角和投影

123

我已经阅读了有关为添加阴影而添加第二个视图的各种帖子,但如果我想在 UICollectionViewCell 中添加它,我仍然无法使其工作。 我对 UICollectionViewCell 进行了子类化,这是我添加各种 UI 元素到单元格内容视图并将阴影添加到层中的代码:

[self.contentView setBackgroundColor:[UIColor whiteColor]];

self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(0, 1);
self.layer.shadowRadius = 1.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.5;
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.bounds] CGPath]];

我想知道如何为 UICollectionViewCell 添加圆角和阴影。


我认为你需要改进你的问题,让别人能够理解。你所问的内容非常混乱。 - Dinesh Raja
好的,已更新。我只想知道如何将圆角和阴影添加到UICollectionViewCell中。 - Vincent Yiu
稍微离题一下 - 在这种情况下使用shadowRadius或setShadowPath,两者都使用没有任何意义,因为它们在本质上是相同的指令(所有圆角)。当您想要更复杂的形状或不应用于所有角落的圆角时,需要使用阴影路径。 - Oly Dungey
17个回答

209

这两种解决方案都对我无效。如果您将所有子视图放入UICollectionViewCell内容视图中(您可能已经这样做了),则可以在单元格的层上设置阴影,在contentView的层上设置边框以实现两个结果。

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 blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0f);
cell.layer.shadowRadius = 2.0f;
cell.layer.shadowOpacity = 0.5f;
cell.layer.masksToBounds = NO;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:cell.contentView.layer.cornerRadius].CGPath;

Swift 3.0

self.contentView.layer.cornerRadius = 2.0
self.contentView.layer.borderWidth = 1.0
self.contentView.layer.borderColor = UIColor.clear.cgColor
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 2.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.contentView.layer.cornerRadius).cgPath

11
在我添加了 cell.layer.backgroundColor = [UIColor clearColor].CGColor; 后,这个方法对我很有效。 - nacross
2
你有什么想法,为什么这只会将我的顶部角落进行四舍五入? - user3344977
@user3344977 可能是底部被裁剪了?也就是说,角落被圆化了,但在单元格的可见部分下面。 - CoderNinja
5
我发现这让我的上角变圆了,但是下角没有跟着圆润。 - fatuhoku
2
当您选择/取消选择/移动单元格时,如何使角落保持圆形?每当我在单元格上呼吸后,它最初正确绘制后我的角落就会变成方形。 - Adrian
显示剩余7条评论

36

Swift 3 版本:

cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderWidth = 1.0

cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true

cell.layer.shadowColor = UIColor.gray.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

我需要在每个单元格的右下角添加阴影效果,但是代码上面的方式会用阴影颜色填充单元格... - Joe Sene

28

如果有帮助的话:以下是将角落进行圆角处理的 Swift 代码:

cell.layer.cornerRadius = 10
cell.layer.masksToBounds = true

cell是一个变量,控制着单元格的显示。通常,在 override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 中会使用它。

祝愉快!


26

这是我的答案,与其他答案相似,但我在层上添加了一个角半径,否则角落将填充不正确。此外,这可以作为 UICollectionViewCell 的一个好的扩展。

extension UICollectionViewCell {
    func shadowDecorate() {
        let radius: CGFloat = 10
        contentView.layer.cornerRadius = radius
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor.clear.cgColor
        contentView.layer.masksToBounds = true
    
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOffset = CGSize(width: 0, height: 1.0)
        layer.shadowRadius = 2.0
        layer.shadowOpacity = 0.5
        layer.masksToBounds = false
        layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
        layer.cornerRadius = radius
    }
}

你可以在数据源的collectionView(_:cellForItemAt:)方法中一旦取出你的单元格,就可以调用它。

23

这里是更新后的 Swift 4 解决方案,用于圆角化所有角而不仅仅是顶部角:

contentView.layer.cornerRadius = 6.0
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true

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

1
也适用于Swift 4.2,谢谢。 - ShadeToD
4
我会尽力为您翻译,以下是翻译的内容:我正在寻找一个解决方案……谢谢你年轻的马西莫:'D - Massimo Polimeni
1
也适用于Swift 5.1,非常不错! - SchmidtFx

17

SWIFT 4.2

如果您正在使用cellForItemAt:方法,请将此内容添加到您的自定义单元格或cellForItemAt:方法中,将self -> cell替换为所需内容。

        self.layer.cornerRadius = 10
        self.layer.borderWidth = 1.0
        self.layer.borderColor = UIColor.lightGray.cgColor

        self.layer.backgroundColor = UIColor.white.cgColor
        self.layer.shadowColor = UIColor.gray.cgColor
        self.layer.shadowOffset = CGSize(width: 2.0, height: 4.0)
        self.layer.shadowRadius = 2.0
        self.layer.shadowOpacity = 1.0
        self.layer.masksToBounds = false

这将为您提供一个带有圆角边框和投影阴影的单元格。


16

设置单元格的layer属性,而不是contentView

CALayer * layer = [cell layer];
[layer setShadowOffset:CGSizeMake(0, 2)];
[layer setShadowRadius:1.0];
[layer setShadowColor:[UIColor redColor].CGColor] ;
[layer setShadowOpacity:0.5]; 
[layer setShadowPath:[[UIBezierPath bezierPathWithRect:cell.bounds] CGPath]];

3
这似乎对我没用。我使用类似的代码来处理uitableviewcell,但在collectionviewcell中似乎不起作用。同样的代码在cv单元格中无法正常工作,这很奇怪。 - Jason
我的上面的评论有更新。我发现UICollectionViewCells似乎使用不同的阴影偏移量比UITableViewCells。如果您没有看到阴影,请尝试更改偏移量(增加Y值对我有帮助)。 - Jason

8

您只需要 (a) 设置 cornerRadius 和 (b) 将 shadowPath 设置为一个带有与 cornerRadius 相同半径的圆角矩形:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];

2
这是为什么只圆了我的底部角落的原因? - user3344977
听起来你要舍入的层部分被某些东西遮挡了。没有详细信息,无法进一步解决问题。 - Timothy Moose
嗨,蒂姆,我刚刚问了这个问题。我有一种感觉你能很快解决它。是因为我的单元格只有底部或“下方”有阴影吗?https://dev59.com/Nobca4cB1Zd3GeqPbd9B - user3344977

7
这是我的解决方案。它与其他答案类似,但有一个关键的区别。它不会创建依赖于视图边界的路径。每当您基于边界创建路径并将其提供给层时,如果其正在调整大小,则可能会遇到问题,并需要设置方法来更新路径。
一个更简单的解决方案是避免使用任何与边界相关的内容。
let radius: CGFloat = 10

self.contentView.layer.cornerRadius = radius
// Always mask the inside view
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1.0)
self.layer.shadowRadius = 3.0
self.layer.shadowOpacity = 0.5
// Never mask the shadow as it falls outside the view
self.layer.masksToBounds = false

// Matching the contentView radius here will keep the shadow
// in sync with the contentView's rounded shape
self.layer.cornerRadius = radius

现在,当单元格大小改变时,视图API会在内部完成所有工作。

在我看来,这是最干净的答案。喜欢保持半径同步的想法。 - Kirill
这个可以运行,但是当你尝试滚动时可能会出现性能问题。 - teradyl

6

我需要对Swift进行一些轻微的更改:

cell.contentView.layer.cornerRadius = 2.0;
cell.contentView.layer.borderWidth = 1.0;
cell.contentView.layer.borderColor = UIColor.clearColor().CGColor;
cell.contentView.layer.masksToBounds = true;

cell.layer.shadowColor = UIColor.grayColor().CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接