Search code examples
iosswiftcalayershadow

How to create the shadow of material-like table view cells?


I am trying to make my table view cells look "material". Here is something similar to what I want to do (source):

enter image description here

Note that there is a shadow around the whole table view in the above image. What I want is that shadow, but applied to each table view cell, instead of the whole table view.

I first designed my cell in an XIB file. I put a UIView called containerView as a subview of the content view. I added constraints so that the containerView has a top, bottom, left, right margin of 8. This is so that the containerView is a little smaller than the content view, so that the shadow I put on it will be visible.

I also added a UILabel called label as the subview of containerView to show some text.

This is the UITableViewCell subclass:

class QueueItemCell: UITableViewCell {
    @IBOutlet var label: UILabel!
    @IBOutlet var container: UIView!

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
        ...
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        ...
    }

    override func awakeFromNib() {
        container.layer.shadowColor = UIColor.black.cgColor
        container.layer.shadowOpacity = 0.7
        container.layer.shadowOffset = CGSize(width: 3, height: 9)
        container.layer.shadowRadius = 4
        container.layer.cornerRadius = 4
        container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath
        selectionStyle = .none
    }
}

There is nothing special about the data source and delegate methods except that I set the cells' height to 61 in heightForRowAt.

When I run the app, I got something like this:

enter image description here

The shadow on the bottom and left edges are quite good. But the right edge is a total disaster. The top edge also does not have a shadow, which is undesirable. I tried to do trial and error with shadowPath and shadowOffset but there's always one or two edges that looks bad.

How can I achieve a shadow on all edges of the cell, as shown in the first image?


Solution

  • in awakeFromNib you have wrong view size. You need to move container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath into layoutSubviews

    or remove this code

    container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: 4).cgPath
    

    so shadow will be configured automatically