Search code examples
iosswiftuitableviewuicollectionviewautolayout

Auto-sizing UITableViewCell which contains UICollectionView


I am having troubles with an autosizing UITableViewCell which contains a UICollectionView. The view hierarchy is roughly like this

UITableViewCell
-- Content View
---- Custom View
------ UIStackView (vertical)
--------- UILabel
--------- UICollectionView (vertical flow layout)

When the UITableViewCell is created or reused, the collectionView receives a datasource which it then starts to process. I need all cells of the collectionView to show in the tableViewCell, so I observe changes to the collectionView's content size in the Custom View like this

    self.collectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.old, context: nil)

Once the collectionView finished rendering its content, I read its contentSize and set the height constraint of the collection view accordingly. This works fine.

The problem now is that all values calculate correctly, but the cell size does not change in the tableView. There are no autolayout errors or warnings in the console, so I assume all constraints are correct. The label in the stackView is also autosizing and this works fine.

I can pass info about the new contentSize of the stackView all the way up to the TableViewController, but I don't know what to call where to force autolayout to recalculate the height of an individual cell.

If I call tableView.reloadData() at the controller level if the height constraint of the collectionView in a cell does not match its content size, it does work. But it causes a delay and is obviously too expensive.

If I pass the cell that changed to the tableView and ask it to reload just the cell, the tableView does not find the indexPath of the cell (probably because it is still off screen). So this approach does not work.

Thanks!


Solution

  • First of all thanks to everybody for their responses!

    After two days of pulling out my hair, it looks like UITableViewCell layout not updating until cell is reused solved it for me.

    The problem was the missing

        cell.layoutIfNeeded()
    

    at the end of

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    

    Here you can see what it looks like now. The setup is like in the original question.

    Again thanks everybody for your pointers!

    Here you can see the result