4
votes

I'm trying to do something fairly simple, but I keep getting errors.

I have a UITableView with multiple sections. Each section has a header and one UITableViewCell. Within each cell is a UICollectionView. All of these views must be created programmatically (I can't use storyboard solutions).

The problem is when I try to size and position the UICollectionView. I would like the UICollectionView to fill the entire UITableViewCell, so at first I tried to size the UICollectionView in the UITableViewCell's init method using self.frame like so:

var collectionView: UICollectionView?
let collectionViewLayout: UICollectionViewFlowLayout!

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {

        self.collectionViewLayout = UICollectionViewFlowLayout()
        self.collectionViewLayout.sectionInset = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
        self.collectionViewLayout.scrollDirection = .vertical

        super.init(style: style, reuseIdentifier: reuseIdentifier)

        let frame = CGRect(x: 0.0, y: 0.0, width: self.frame.width, height: self.frame.height)
        self.collectionView = UICollectionView(frame: frame, collectionViewLayout: self.collectionViewLayout)

        self.collectionView?.dataSource = self
        self.collectionView?.delegate = self
}

However, I think that the UITableViewCell's frame is not set at this time (the init method call), and so the UICollectionView is sized improperly. Is that correct?

Next, I tried using layout anchors, like so:

collectionView?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

This gave me a layout constraint error and said 'UICollectionViewProject[63851:2306772] [LayoutConstraints] Unable to simultaneously satisfy constraints.' I don't understand how thats possible. I only added one constraint, there is nothing in storyboard, what constraints could it possibly be breaking?

Somehow I need to make this UICollectionView the same size as the UITableViewCell and fit inside it perfectly.

2

2 Answers

4
votes

In your code you have added just 1 constraint - bottomAnchor. Autolayout doesn't work like that. Just add all the required constraints after adding UICollectionView as subview of UITableViewCell, i.e.

override init(style: UITableViewCellStyle, reuseIdentifier: String?)
{
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    self.collectionViewLayout = UICollectionViewFlowLayout()
    self.collectionViewLayout.sectionInset = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
    self.collectionViewLayout.scrollDirection = .vertical

    let frame = CGRect(x: 0.0, y: 0.0, width: self.frame.width, height: self.frame.height)
    self.collectionView = UICollectionView(frame: frame, collectionViewLayout: self.collectionViewLayout)
    self.collectionView?.translatesAutoresizingMaskIntoConstraints = false
    self.addSubview(self.collectionView!)

    NSLayoutConstraint.activate([
        self.collectionView!.topAnchor.constraint(equalTo: self.topAnchor),
        self.collectionView!.bottomAnchor.constraint(equalTo: self.bottomAnchor),
        self.collectionView!.leftAnchor.constraint(equalTo: self.leftAnchor),
        self.collectionView!.rightAnchor.constraint(equalTo: self.rightAnchor),
        ])

    self.collectionView?.dataSource = self
    self.collectionView?.delegate = self
}
1
votes

The size you're setting for you collection view will be overridden based on autolayout (automatically translated from the collection view default autoresizing masks) so you need to set up the appropriate constraints.

If you want your collection view to fill up your whole cell, try adding the following code at the end of your init method:

collectionView.translatesAutoresizingMaskIntoConstraints = false
addSubview(collectionView)

let layoutAttributes: [NSLayoutAttribute] = [.top, .bottom, .leading, .trailing]
let constraints = layoutAttributes.map {
    NSLayoutConstraint(item: self, attribute: $0, relatedBy: .equal, toItem: collectionView, attribute: $0, multiplier: 1.0, constant: 0.0)
}
NSLayoutConstraint.activate(constraints)

Then, you will have to calculate the height of your collection view and tell your table view delegate in the method tableView(_:, heightForRowAt:).