UIKit: TableView with card style Cells

Photo by Esteban Lopez on Unsplash

Today we are going to learn how to make a UITableView with each cell as a Card (rounded corners and drop shadow). Here is the final result:

All right, let’s setup a table view with one prototype cell. In order to get a card-ish cell, we need to use one more view inside the cell’s Content View to act as container for all the cell’s content on which to apply the rounded corners and the drop shadow. So the view hierarchy should look like the following:

As you can see, I added a view named Container View under the Content View of the prototype cell cardCell.

Then I created a subclass of UITableViewCell with the outlets to the cell’s content where I do the following:

@IBOutlet
weak var containerView: UIView! {
didSet {
// Make it card-like
containerView.layer.cornerRadius = 10
containerView.layer.shadowOpacity = 1
containerView.layer.shadowRadius = 2
containerView.layer.shadowColor = UIColor(named: "Orange")?.cgColor
containerView.layer.shadowOffset = CGSize(width: 3, height: 3)
containerView.backgroundColor = UIColor(named: "Red")
}
}

Well this code should be familiar to who has read my previous posts UIKit: Rounded Views and UIKit: View Shadow, anyway all that this code does is making the container view’s corners rounded by 10 points and setting up its shadow.

Hurray, it was simple uhu?! Let’s run the code and see the result…

The card for Buffon who is the captain of the best Italian team, that is Juventus 😛, has an image view (the captain strip) with the same card color and it does not get clipped, making the top-right corner of the card seem not rounded. Let’s make the image view stick to the card bounds with containerView.layer.masksToBounds = true. Run the code again and see if we fix the problem:

Holy Moly 😱! The image gets clipped and so does the shadow. Well, looking through the Internet, the only solution that seems to work is having one more view in the cell view hierarchy on which to apply shadow under the container view that clips its content, like the following:

So here is the problem: when you set the layer’s property masksToBounds to true, all its sublayers and all the subviews of the view owning this layer (I think it’s the same since the view is just a delegate of a layer) gets clipped so the solution is to put the shadow on the topmost view and to set the rounded corners and the masksToBounds on the view below it. So in the example, the Container View has the shadow and the Clipping View has the rounded corners that clips the cell’s content.

@IBOutlet
weak var containerView: UIView! {
didSet {
containerView.backgroundColor = UIColor.clear
containerView.layer.shadowOpacity = 1
containerView.layer.shadowRadius = 2
containerView.layer.shadowColor = UIColor(named: "Orange")?.cgColor
containerView.layer.shadowOffset = CGSize(width: 3, height: 3)
}
}
@IBOutlet
weak var clippingView: UIView! {
didSet {
clippingView.layer.cornerRadius = 10
clippingView.backgroundColor = UIColor(named: "Red")
clippingView.layer.masksToBounds = true
}
}

That’s it. I hope to have helped someone since I see that a lot of people use this style for the table views and even if the solution seems straightforward, it took a lot of time to me to come up with it. Hope you saved some time that you can use on the creative process of your App.

Bye bye 👋