Rounded corners and a shadow on UIKit cells
In UIKit you can't simply round a view's corners and give the same view a shadow — getting both takes a hack. In a collection view it gets worse: every cell, header and footer needs its own shadow setup and its own offset.
Put the shadow on the collection view once, and keep the rounded corners on a background view inside each reusable view. This is still a correct way to work with UIKit, and it takes about a minute.
Why one view can't have both
A card usually has content that must follow its rounded corners: an image, a colored header, a separator. For that the card needs clipsToBounds = true, and clipping also removes the shadow. Turn clipping off and the shadow comes back, but the content no longer respects the corners:

Shadow on the card, no clipping: the indigo strip sticks out of the rounded corners.
The usual way out is a shadow set up in every reusable view, with its own offset. That is the routine this trick removes.
The usual per-view shadow
Shadow code on each reusable view usually looks like this:
yourView.layer.shadowColor = UIColor.red.cgColor
yourView.layer.shadowOpacity = 0.25
yourView.layer.shadowOffset = CGSize(width: 1, height: 1)
yourView.layer.shadowRadius = 2
The same lines repeat in every cell, header and footer, each with its own offset.
Clear backgrounds, one rounded background view
Set the background of the collection view and of every reusable view to .clear.
The only exception is the views in the storyboard that act as the visible background. That can be any UIView subclass with any settings, cornerRadius included. These views can keep clipsToBounds = true: the shadow no longer lives on them.
Move the shadow to the collection view
Take the shadow setup out of layoutSubviews() of the reusable view and put it into viewWillLayoutSubviews() or viewDidLayoutSubviews() of the view controller. Use the collection view as yourView:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.layer.shadowColor = UIColor.red.cgColor
collectionView.layer.shadowOpacity = 0.25
collectionView.layer.shadowOffset = CGSize(width: 1, height: 1)
collectionView.layer.shadowRadius = 2
}
That's it:

Cards clipped to their rounded corners, cells and collection view clear, one shadow on the collection view.
Why it works
The shadow of the collection view's layer takes the shape of what is visible inside it — all the cells together. With clear backgrounds, the only visible things are the rounded background views, so the one shadow gets their rounded shape. The cards stay clipped, and the shadow is set up in one place instead of in every reusable view.
Where it breaks
Everything between the collection view and the rounded view has to stay clear. If a cell keeps its own background color, the shadow follows the cell's rectangle instead of the card:

The same setup with backgroundColor = .white on the cell: square corners and a rectangular shadow.
The fix: final version
Make every layer between the collection view and the card clear: the cell, its contentView and the collection view. The card keeps its color, its corners and its clipping. The shadow is set once, on the collection view.
final class CardCell: UICollectionViewCell {
let card = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
contentView.backgroundColor = .clear
card.backgroundColor = .white
card.layer.cornerRadius = 16
card.clipsToBounds = true
card.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(card)
NSLayoutConstraint.activate([
card.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
card.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
card.topAnchor.constraint(equalTo: contentView.topAnchor),
card.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
])
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
final class CardsViewController: UIViewController {
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// … create the collection view and register CardCell
collectionView.backgroundColor = .clear
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.layer.shadowColor = UIColor.black.cgColor
collectionView.layer.shadowOpacity = 0.35
collectionView.layer.shadowOffset = CGSize(width: 0, height: 4)
collectionView.layer.shadowRadius = 8
}
}
With the cell background back to .clear, the same cards get rounded corners and a shadow that follows them:

After the fix: cell and contentView clear, card clipped, one shadow on the collection view.