Search code examples
iosswiftuicollectionviewxibnib

Set width of custom UIView nib to it's parent CollectionViewCell


This is what I have:

A Collection View with 2 columns with each an equal distance apart.

Each cell loads SmallCardView.xib. The SmallCardView contains a square image with some text below.

The problem:

I want the width of the view to match that of it's parent (the cell). This is best illustrated by comparing screen sizes

Screen size comparison

As you can see above, the cell (purple outline) sizes correctly on both screens but the SmallCardView remains the same size

Here is the code in my Collection View Controller:

viewDidLoad -

private let spacing: CGFloat = 20.0

override func viewDidLoad() {
    super.viewDidLoad()

    let layout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: spacing, left: spacing, bottom: spacing, right: spacing)
    self.collectionView?.collectionViewLayout = layout
}

sizeForItemAt -

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let numberOfItemsPerRow: CGFloat = 2
    let spacingBetweenCells: CGFloat = 20

    let totalSpacing = (2 * self.spacing) + ((numberOfItemsPerRow - 1) * spacingBetweenCells) // Amount of total spacing in a row

    if let collection = self.collectionView {
        let width = (collection.bounds.width - totalSpacing)/numberOfItemsPerRow
        return CGSize(width: width, height: width * 1.2)
    } else {
        return CGSize(width: 0, height: 0)
    }
}

Thanks!


Solution

  • You can embed view with constraints to edges as:

    extension UIView {
    
        func makeEdges(to view: UIView, useMargins: Bool = false) -> [NSLayoutConstraint] {
            return [
                (useMargins ? layoutMarginsGuide.leftAnchor : leftAnchor).constraint(equalTo: view.leftAnchor),
                (useMargins ? layoutMarginsGuide.rightAnchor : rightAnchor).constraint(equalTo: view.rightAnchor),
                (useMargins ? layoutMarginsGuide.topAnchor : topAnchor).constraint(equalTo: view.topAnchor),
                (useMargins ? layoutMarginsGuide.bottomAnchor : bottomAnchor).constraint(equalTo: view.bottomAnchor)
            ]
        }
    
        func edges(to view: UIView, useMargins: Bool = false) {
            NSLayoutConstraint.activate(makeEdges(to: view, useMargins: useMargins))
        }
    }
    

    And use it as:

    let cardView = ...
    cardView.translatesAutoresizingMaskIntoConstraints = false
    let cell = ...
    cell.contentView.addSubview(cardView)
    cell.contentView.edges(to: cardView, useMargins: true)