I have UITableView
with one section (1 header view + 100 rows). Its vertical constraints are to top view’s bottom and to superview’s bottom (not bottom safe area).
I provided all the necessary heights manually with UITableViewDelegate
:
- section header height
- first and last cell height
- other cells height
If I sum all these heights i get ~6000px but tableView.contentSize.height
returns ~4500 until I scroll to the bottom of the table. And this happens even with default cells.
I understand that I can calculate everything manually but why table has wrong content size if all its inner element heights are predefined?
2
Answers
Found a solution for my case (when all the table items' heights are predefined): https://developer.apple.com/forums/thread/81895
It seems
heightForRow
delegate method determines the height of the row which is drawn/visible on the screen but is not properly involved incontentSize
calculation.estimatedHeightForRowAt
looks like the opposite method. It determines the height of the row forcontentSize
calculation but without ofheightForRow
visible rows have the default height.So it is necessary to implement both
heightForRow
andestimatedHeightForRowAt
methods for this case.The same is for header/footer heights (if these items are displayed)
A
UITableView
– like most components – does a lot of "behind the scenes" work. When it loads, it doesn’t need to calculate or render its entire potential content size.Quick example to demonstrate…
simple single label cell class
basic table view controller
Note in the controller class, we have this property:
and we’ve implemented
heightForRowAt
like this:Every time
heightForRowAt
is called, we’ll set that property to the highest row number.In
didSelectRowAt
, we’ll print that property and the table view’s.contentSize.height
.On launch, on an iPhone 14 Pro, 14 rows are visible. Selecting a row outputs this to the debug console:
As we see,
heightForRowAt
has been called only for the first 14 rows.Scrolling a bit and selecting rows outputs this:
Once we’ve scrolled far enough so that
heightForRowAt
has been called on ALL the rows, we now have a validtableView.contentSize.height
.