向 UICollectionViewCell 添加圆角和阴影

Posted

技术标签:

【中文标题】向 UICollectionViewCell 添加圆角和阴影【英文标题】:Adding rounded corner and drop shadow to UICollectionViewCell 【发布时间】:2012-11-22 03:10:57 【问题描述】:

所以我已经阅读了有关添加第二个视图以添加阴影的各种帖子,但如果我想将它添加到 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添加圆角和阴影。

【问题讨论】:

我认为你需要改进你的问题才能被别人理解。你问的真的很乱 ok 更新了,我只想知道如何给 UICollectionViewCell 添加圆角和阴影 稍微抛开 - 使用 shadowRadius 或 setShadowPath,两者都做没有意义,因为在这种情况下它们本质上是相同的指令(所有圆角)。如果您希望更复杂的形状或圆角不应用于所有角,则需要使用阴影路径。 【参考方案1】:

这些解决方案都不适合我。如果您将所有子视图放入 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;

斯威夫特 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

【讨论】:

在我添加cell.layer.backgroundColor = [UIColor clearColor].CGColor;后,这对我来说效果很好 知道为什么这只会使我的顶角变圆吗? @user3344977 也许底部被剪裁了?因为角落是圆形的,但它在单元格的可见部分下方 我发现这会使我的顶角变圆,而不是底角。 当您选择/取消选择/移动单元格时,如何让角保持圆形?在最初正确绘制后,每当我在单元格上呼吸时,我的角都会变直。【参考方案2】:

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

【讨论】:

我需要在每个单元格的右上角和底部添加阴影效果,上面代码的工作方式是用阴影颜色填充单元格...【参考方案3】:

如果有帮助:这里是圆角的快捷方式:

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

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

享受吧!

【讨论】:

【参考方案4】:

这里是 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

【讨论】:

也可以在 swift 4,2 中使用,谢谢 我正在寻找解决方案...感谢年轻的马西莫:'D 也适用于 Swift 5.1,相当不错!【参考方案5】:

这是我的答案,与其他答案很接近,但我在图层中添加了角半径,否则角将无法正确填充。此外,这对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:) 中调用它。

【讨论】:

【参考方案6】:

为单元格设置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]];

【讨论】:

这似乎对我不起作用。我对 uitableviewcell 使用了类似的代码,但它似乎在 collectionviewcell 中不起作用。奇怪的是,相同的代码在 cv 单元格中不起作用。 我上述评论的更新。我发现 UICollectionViewCells 似乎使用了与 UITableViewCells 不同的阴影偏移量。如果您没有看到阴影,请尝试更改偏移量(增加 Y 值对我有帮助)。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

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

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

【讨论】:

知道为什么这只会使我的底角变圆吗? 听起来你正在舍入的任何层都被某些东西部分遮盖了。没有细节就不能再进一步了。 嘿蒂姆,我刚问了这个问题。我有一种感觉,你会很快得到它。是因为我只有在单元格的底部/“下方”有阴影吗? ***.com/q/27929735/3344977【参考方案9】:

这是我对解决方案的看法。它与其他答案相似,但有一个关键区别。它不会创建依赖于视图边界的路径。每当您基于边界创建路径并将其提供给图层时,您可能会在调整大小时遇到​​问题,并且需要设置方法来更新路径。

一个更简单的解决方案是避免使用任何依赖于边界的东西。

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 将在内部完成所有工作。

【讨论】:

我认为最干净的答案。喜欢保持半径同步的想法。【参考方案10】:

我不得不为 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;

【讨论】:

【参考方案11】:

我使用以下方法来完成这种效果:

extension UICollectionViewCell 
    /// Call this method from `prepareForReuse`, because the cell needs to be already rendered (and have a size) in order for this to work
    func shadowDecorate(radius: CGFloat = 8,
                        shadowColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3),
                        shadowOffset: CGSize = CGSize(width: 0, height: 1.0),
                        shadowRadius: CGFloat = 3,
                        shadowOpacity: Float = 1) 
        contentView.layer.cornerRadius = radius
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor.clear.cgColor
        contentView.layer.masksToBounds = true

        layer.shadowColor = shadowColor.cgColor
        layer.shadowOffset = shadowOffset
        layer.shadowRadius = shadowRadius
        layer.shadowOpacity = shadowOpacity
        layer.masksToBounds = false
        layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
        layer.cornerRadius = radius
    

【讨论】:

【参考方案12】:

Mike Sabatini 的答案很好,如果您直接在 collectionView cellForItemAt 上配置单元格属性,但如果您尝试在自定义 UICollectionViewCell 子类的 awakeFromNib() 中设置它们,则会以错误的 bezierPath 设置结束与之前在 Storyboard (IB) 中设置的宽度和高度不匹配的设备。

我的解决方案是在 UICollectionViewCell 的子类中创建一个 func 并像这样从 cellForItemAt 调用它:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as? CustomCollectionViewCell
        cell.configure())
        return cell
    
    else 
        return UICollectionViewCell()
    

在 CustomCollectionViewCell.swift 上:

class CustomCollectionViewCell: UICollectionViewCell
    func configure() 
    contentView.layer.cornerRadius = 20
    contentView.layer.borderWidth = 1.0
    contentView.layer.borderColor = UIColor.clear.cgColor
    contentView.layer.masksToBounds = true
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0, height: 2.0)
    layer.shadowRadius = 2.0
    layer.shadowOpacity = 0.5
    layer.masksToBounds = false
    layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath
 

【讨论】:

【参考方案13】:

这个对我有用

cell.contentView.layer.cornerRadius = 5.0
cell.contentView.layer.borderColor = UIColor.gray.withAlphaComponent(0.5).cgColor
cell.contentView.layer.borderWidth = 0.5

let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: cell.contentView.frame.size.height - width, width:  cell.contentView.frame.size.width, height: cell.contentView.frame.size.height)

border.borderWidth = width
cell.contentView.layer.addSublayer(border)
cell.contentView.layer.masksToBounds = true
cell.contentView.clipsToBounds = true

【讨论】:

【参考方案14】:

您可以在创建UICollectionViewCell时在UICollectionViewDataSource方法中设置阴影颜色、半径和偏移量

cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 1.0
cell.layer.shadowOpacity = 0.5
cell.layer.masksToBounds = false

【讨论】:

【参考方案15】:

我发现了一件重要的事情:UICollectionViewCell 必须将 backgroundColor 设置为 clear 颜色才能使上述这些工作。

【讨论】:

这对于实现不切断阴影非常重要!不要忽视这个答案,非常感谢,伙计!【参考方案16】:

Swift 5、Xcode 13、iOS 14

首先将您的收藏配置如下:

self.collectionView.clipsToBounds = false

然后配置您的单元格,如下所示:

override func awakeFromNib() 
    super.awakeFromNib()
    
    self.configView()

    
private func configView() 
    self.clipsToBounds = false
    self.backgroundColor = .systemBackground
    self.layer.cornerRadius = 10
    self.layer.shadowColor = UIColor.black.cgColor
    self.layer.shadowOffset = CGSize(width: 0, height: 0.0)
    self.layer.shadowRadius = 10
    self.layer.shadowOpacity = 0.2

注意这两个“clipToBounds = false”命令。

就是这样。

【讨论】:

它不起作用,单元格上的clipsToBounds = false会取消圆角半径。您需要在 contentView 上应用圆角半径并在单元格本身上应用阴影

以上是关于向 UICollectionViewCell 添加圆角和阴影的主要内容,如果未能解决你的问题,请参考以下文章

向 UICollectionViewCell 添加覆盖视图 - 不断覆盖

如何使用清晰的背景颜色向 UICollectionViewCell 添加阴影?

使用 xib 将手势添加到 UICollectionViewCell 子视图

延迟加载 UICollectionViewCell 的自定义子视图

UICollectionViewCell 向 UICollectionView didSelect 发出信号

将 UILabel 固定到 UICollectionViewCell contentView 按钮的自动布局约束