1

I have a UICollectionView inside a UITableViewCell.

I am setting the UITableViewCell row height to be dynamic:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
   return UITableViewAutomaticDimension
}

My UICollectionView has a variable number of items:

func collectionView(_ collectionView: UICollectionView,
                    numberOfItemsInSection section: Int) -> Int {
    return items.count
}

Now here is the sequence of events that is causing me headache:

  • UITableView calls delegate cellForRowAt and dequeues a UITableViewCell with dynamic height
  • In the NEXT loop cycle, the UICollectionView inside the UITableViewCell calls on its delegates numberOfItemsInSection and cellForItemAt to determine the UICollectionView contentSize.
  • Now it's too late since the UITableViewCell has already been dynamically sized with a UICollectionView that has no cells, and so the UITablewViewCell height is too short and does NOT fit the UICollectionView properly.

I have found an ugly work around by reloading the UITableView but I don't like this approach at all:

private func reloadCell() {
    let when = DispatchTime.now()
    DispatchQueue.main.asyncAfter(deadline: when) {
        if let indexPath = self.chatViewController?.chatTableView.indexPath(for: self) {
            self.tableView.reloadRows(at: [indexPath], with: .none)
        }
    }
}

My question is if I can force the UICollectionView to reload and call it's delegates immediately so that the UITableViewCell height can be computed by the autolayout engine correctly?

etayluz
  • 15,920
  • 23
  • 106
  • 151
  • Is your collection view height dynamic or tableview cell height? – Kirti Parghi Dec 04 '16 at 09:39
  • The UICollectionView height is dynamic (depends on number of items) and therefore the UITableViewCell (which contains the UICollectionView) is also dynamic – etayluz Dec 04 '16 at 09:41
  • 1
    Did you ever manage to find a solution for this, I currently have this issue. – Niall Kiddle Apr 19 '18 at 22:19
  • Create a subclass for collection view and override the intrinsicContentSize. [Refer here](https://stackoverflow.com/questions/49931158/dynamic-uicollectionview-inside-dynamic-uitableviewcell/52247590#52247590) – Learner Sep 09 '18 at 18:47

1 Answers1

0

In viewDidLoad, add observer for collection view,

 collectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old.union(NSKeyValueObservingOptions.New), context: self)

Now, overrider observe value for keypath for controlling collection view reload completion handler through KVO.

 override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) 
 {
    // You will get here when the reloadData finished 
 }

Now, in view Will Disappear remove observer that was set for collection view.

 override func viewWillDisappear(_ animated: Bool) {
 {
   // remove collection view observer   
 }

Same logic will be applied for tableview in order to get fully visible tableview cell containing collection view inside it.

Kirti Parghi
  • 1,142
  • 3
  • 14
  • 31