UITableViewCell:圆角和阴影

问题描述 投票:38回答:10

我正在改变UITableViewCell的宽度,以便单元格更小,但用户仍然可以沿着tableview的边缘滚动。

override func layoutSubviews() {        
    // Set the width of the cell
    self.bounds = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width - 40, self.bounds.size.height)
    super.layoutSubviews()
}

然后我绕过角落:

cell.layer.cornerRadius = 8
cell.layer.masksToBounds = true

到目前为止都很好。阴影会出现问题。边界被掩盖,因此阴影显然不会出现。我已经查找了其他答案,但似乎无法弄清楚如何沿着边界圆角并显示阴影。

cell.layer.shadowOffset = CGSizeMake(0, 0)
cell.layer.shadowColor = UIColor.blackColor().CGColor
cell.layer.shadowOpacity = 0.23
cell.layer.shadowRadius = 4

所以我的问题 - 如何减小宽度,绕角,并同时为UITableViewCell添加阴影?

更新:尝试R Moyer的回答

Trying R Moyer's answer

swift uitableview
10个回答
80
投票

这个问题来得很愉快!我自己也完全解决了同样的问题。

  1. 在单元格的内容视图中创建一个UIView(让我们将其称为mainBackground)。这将包含您所有单元格的内容。定位它并在故事板中应用必要的约束。
  2. 创建另一个UIView。这个将是带阴影的那个(让我们把它称为shadowLayer)。完全按照mainBackground的定位,但在它后面,并应用相同的约束。
  3. 现在您应该可以设置圆角和阴影,如下所示: cell.mainBackground.layer.cornerRadius = 8 cell.mainBackground.layer.masksToBounds = true cell.shadowLayer.layer.masksToBounds = false cell.shadowLayer.layer.shadowOffset = CGSizeMake(0, 0) cell.shadowLayer.layer.shadowColor = UIColor.blackColor().CGColor cell.shadowLayer.layer.shadowOpacity = 0.23 cell.shadowLayer.layer.shadowRadius = 4

但是,这里的问题是:计算每个单元格的阴影是一项缓慢的任务。当您滚动表格时,您会注意到一些严重的延迟。解决这个问题的最好方法是为阴影定义一个UIBezierPath,然后栅格化它。所以你可能想这样做:

cell.shadowLayer.layer.shadowPath = UIBezierPath(roundedRect: cell.shadowLayer.bounds, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: 8, height: 8)).CGPath
cell.shadowLayer.layer.shouldRasterize = true
cell.shadowLayer.layer.rasterizationScale = UIScreen.mainScreen().scale

但这会产生一个新问题! UIBezierPath的形状取决于shadowLayer的界限,但是在调用cellForRowAtIndexPath时没有正确设置边界。所以,你需要根据shadowPath的界限调整shadowLayer。执行此操作的最佳方法是继承UIView,并将属性观察器添加到bounds属性。然后在didSet中设置阴影的所有属性。请记住在故事板中更改shadowLayer的类以匹配新的子类。

class ShadowView: UIView {
    override var bounds: CGRect {
        didSet {
            setupShadow()
        }
    }

    private func setupShadow() {
        self.layer.cornerRadius = 8
        self.layer.shadowOffset = CGSize(width: 0, height: 3)
        self.layer.shadowRadius = 3
        self.layer.shadowOpacity = 0.3
        self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 8, height: 8)).cgPath
        self.layer.shouldRasterize = true
        self.layer.rasterizationScale = UIScreen.main.scale
    }
}

0
投票

1-创建自定义TableViewCell类。将以下代码粘贴到创建IBOutlets的类级别。 exerciseView是要在其中舍入的ContentView内部的视图。

@IBOutlet weak var exerciseView: UIView! {
        didSet {
            self.exerciseView.layer.cornerRadius = 15
            self.exerciseView.layer.masksToBounds = true
        }
    }

didSet基本上是变量观察者。您可以在awakeFromNib函数中执行此操作以及:

self.exerciseView.layer.cornerRadius = 15
self.exerciseView.layer.masksToBounds = true

21
投票

接受的答案有效,但添加额外的子视图以获得此效果几乎没有任何意义。这是有效的解决方案。

第1步:添加阴影和角半径

// do this in one of the init methods
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    // add shadow on cell
    backgroundColor = .clear // very important
    layer.masksToBounds = false
    layer.shadowOpacity = 0.23
    layer.shadowRadius = 4
    layer.shadowOffset = CGSize(width: 0, height: 0)
    layer.shadowColor = UIColor.blackColor().CGColor

    // add corner radius on `contentView`
    contentView.backgroundColor = .white
    contentView.layer.cornerRadius = 8
}

第二步:掩盖在willDisplay的界限

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // this will turn on `masksToBounds` just before showing the cell
    cell.contentView.layer.masksToBounds = true
}

额外奖励:平滑滚动

// if you do not set `shadowPath` you'll notice laggy scrolling
// add this in `willDisplay` method
let radius = cell.contentView.layer.cornerRadius
cell.layer.shadowPath = UIBezierPath(roundedRect: cell.bounds, cornerRadius: radius).cgPath

20
投票
cell.layer.cornerRadius = 10
cell.layer.masksToBounds = true

13
投票

要为单元格创建阴影和角落,您只需要一个backView。请参阅下面的示例。

enter image description here

你必须添加backView并设置leadingtrailingtopbottom约束等于Content view。把你的内容放到backView有适当的限制,但要确保你的内容不超过backView

之后在您的单元格初始化代码中添加以下行:

override func awakeFromNib() {
    super.awakeFromNib()

    backgroundColor = Colors.colorClear

    self.backView.layer.borderWidth = 1
    self.backView.layer.cornerRadius = 3
    self.backView.layer.borderColor = Colors.colorClear.cgColor
    self.backView.layer.masksToBounds = true

    self.layer.shadowOpacity = 0.18
    self.layer.shadowOffset = CGSize(width: 0, height: 2)
    self.layer.shadowRadius = 2
    self.layer.shadowColor = Colors.colorBlack.cgColor
    self.layer.masksToBounds = false
}

不要忘记为Back View创建IBOutlet。

结果如下:

enter image description here


6
投票

我使用下面的代码实现了相同的功能。但是你将它放在TableViewCell子类的layoutSubviews()方法中。

self.contentView.backgroundColor = [UIColor whiteColor];
self.contentView.layer.cornerRadius = 5;
self.contentView.layer.shadowOffset = CGSizeMake(1, 0);
self.contentView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.contentView.layer.shadowRadius = 5;
self.contentView.layer.shadowOpacity = .25;
CGRect shadowFrame = self.contentView.layer.bounds;
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
self.contentView.layer.shadowPath = shadowPath;

3
投票

您可以尝试一种替代方法,在UIView中使用UITableViewCell。设置UITableViewCell的背景颜色以清除颜色。现在,你可以制作圆角并在UIVIew上添加阴影。这将显示为单元格宽度减小,用户可以沿tableView的边缘滚动。


1
投票

永远不要使用UIBezierPath,bezierPathWithRect:shadowFrame等,因为它非常重,并且在视图顶部绘制一个图层,并且需要再次重新加载表视图以确保单元格以正确的方式呈现,有时甚至重新加载可能没有帮助。而是使用一个部分页眉和页脚,它根据需要具有圆形边缘,并且也在故事板内部,这将使表格视图的滚动和加载非常平滑而没有任何渲染问题(有时称为丢失单元格并出现在滚动上)

在这里参考如何设置圆角的不同整数值:Setting masked corners in Interface Builder

只需为节标题和页脚使用上述值即可。


0
投票

试试这个,它对我有用。

    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

0
投票

它的工作没有额外的意见!

override func awakeFromNib() {
    super.awakeFromNib()

    layer.masksToBounds = false
    layer.cornerRadius = Constants.cornerRadius
}

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    let layer = cell.layer
    layer.shadowOffset = CGSize(width: 0, height: 1)
    layer.shadowRadius = 2
    layer.shadowColor = UIColor.lightGray.cgColor
    layer.shadowOpacity = 0.2
    layer.frame = cell.frame
    cell.tagLabel.text = tagItems[indexPath.row].text

    return cell
}
© www.soinside.com 2019 - 2024. All rights reserved.