3

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!

10
  • please provide expected UI screen shot. i think it is possible with single scroll view, you don't need nesting two scrollview. Commented Mar 7, 2019 at 10:22
  • @SPatel There are no two scrollViews. The tableView has the scrollView, the collectionView is sized to display all cells, so it is not scrolling. Commented Mar 7, 2019 at 10:24
  • I stumbled upon this scenario as well, but I realized it could be heavy for doing this operation as it might not always possible your collectionview cells size layout before tableview cells. In most use case scenario you can maintain a datasource of those heights by calculating them earlier as we only will be specifying collectionview cell size. Commented Mar 7, 2019 at 10:25
  • @Georg i personally suggest you that don't use nested scrollview if possible. Commented Mar 7, 2019 at 10:27
  • Apart from that, would like to point that you can fall into the common bug while nesting scrollviews, you should call collectionview.reloadData() in tablview's dequeue method, because while reusing table cells collectionview get reused its own dequeue method isn't called. This will help - ashfurrow.com/blog/… Commented Mar 7, 2019 at 10:28

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

2 Comments

The only solution that worked for me here: stackoverflow.com/a/65074843/2019384
For me I changed the layout height constraint of the UICollectionView with the content size and wrapped that inside a tableView.beginUpdates() and tableView.endUpdates()
-1

Even thought this is an already answered question. But I have found this easy method in this tutorial to resize the UITableViewCell height according to the UICollectionView height size.

Add a height constraint to the UICollectionView and create an outlet for it in the UITableViewCell and don't forget to disable UICollectionView Scrolling and set its flow to vertical.

@IBOutlet weak var collectionViewHeight: NSLayoutConstraint! 

In the UITableViewDelegate cellForRow method use these

cell.frame = tableView.bounds cell.collectionView.reloadData() cell.layoutIfNeeded() cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height 

I can tell it is working like charm and no need for observes.

Link for full tutorial

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.