UICollectionView Inside A UITableViewCell With Self Sizing

If you are looking for a way to put a collection view inside a table cell without manually calculating table row heights, you are in the right place.

If your app target is iOS 14, you might consider using UICollectionLayoutListConfiguration to construct sections of the collection view as lists like in table views. Here is a WWDC-20 video showing how to do that.

This piece was written when iOS 14 just came out. Many apps still target iOS 13 or earlier. This method is for those apps.

This Github repository contains the complete project: https://github.com/viettran/CollectionViewTableCell. You can clone it to follow along. Below are step-by-step instructions and technical explanations.

Building The Basic

Step 1: Create a custom UITableViewCell to host the collection view.

There is no special setup for this table cell. I would just use XCode to add a new Cocoa Touch class, subclass UITableViewCell and also create XIB file.

Step 2: Put your collection view, if you already have one, in theCollectionViewTableViewCell. If you don’t already have a collection view, create one. In my sample codes, I use UICollectionViewController. However, you can use UIViewController with a custom UICollectionView, if preferred.

Step 3: Put the CollectionViewTableViewCell in your table view if you already have one. If not, create your table view. Also setup your table view to use automatic row height.

Self Sizing

Step 4: Setup a callback when collection view is done laying out.

If you are thinking about using intrinsicContentSize or systemLayoutSizeFitting, it won’t work. Simply because the table view fetches those information before the collection view layouts its subviews. You would have to manually calculate the collection view size. This method, however, is about self sizing - relying on the collection view to layout its subviews.

Step 5: Hook up didLayoutAction in table view cell.

Step 6: Override systemLayoutSizeFitting in UITableViewCell

There are a lot of confusions/discussions/arguments between intrinsicContentSize and systemLayoutSizeFitting (or sizeThatFits). For me, I only use intrinsicContentSize when the view is a leaf in the view hierarchy, like labels or buttons. For views with subviews, I always use systemLayoutSizeFitting. By the way, in this case, intrinsicContentSize won’t work.

The table view, when calculating row height in automaticDimension, will call this method systemLayoutSizeFitting.

I want the collection view to entirely vertically expand without scrolling so I used its contentSize (UICollectionView is a UIScrollView).

Updating table layout without reloading row

Step 7: Useful extensions.

I want to emphasize this part because it’s easily overlooked. Don’t reloadData or reloadRows while you only want to update table layout. All you need to do is to call UITableView ‘s beginUpdates() and endUpdates(). If you don’t want animation, you can wrap it in UIView.performWithoutAnimation().

To make the logic contained in UITableViewCell, we need to be able to access the tableView from the cell. Thus, I created some extensions as below.

Step 8: Update row height.

Now it’s time to implement the callback when the collection view is done laying out: update table view layout.

That’s it! Let me know if you have any feedback. Again, here is the entire code: https://github.com/viettran/CollectionViewTableCell

iPhone developer since 2010