estimatedHeightForRowAtIndexPath can in fact change the final "correct" height of a row?

Fattie picture Fattie · Nov 27, 2013 · Viewed 17.2k times · Source

I've just discovered an astounding problem or counter-intuituve behaviour when using estimatedHeightForRowAtIndexPath

(1) My table has wildly varying row heights. The final results can range from 111 to about 400.

(2) I absolutely perfectly calculate each row height. I have these on hand in an array, that is to say cached.

{Note that this is exactly what, apparently, Apple engineers now recommend...example, point 5 .. Using Auto Layout in UITableView for dynamic cell layouts & variable row heights}

(3) When heightForRowAtIndexPath asks for a height, I do give it absolutely the correct height.

(4) WHen I build the cell, indeed, I build it to exactly the correct height (as in (2) and (3)).

{Note - of course it's iOS that finally sizes the height of a cell, not "me".}

THIS ALL WORKS PERFECTLY.

ie, each cell is built by iOS at exactly the height given in heightForRowAtIndexPath.

Now, I add the code ...

-(CGFloat)tableView:(UITableView *)tableView
    estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 120;
}

IN FACT, THE TABLE NO LONGER WORKS .................. THE ROW HEIGHTS BECOME RANDOM!!!

HAS ANYONE SEEN THIS INCREDIBLE BEHAVIOUR?

I did various tests to try to determine the relationship of what the hell estimatedHeightForRowAtIndexPath does. At first, I thought it might provide a lower bound on the height. So, 150 .. even my smaller cells would incorrectly be 150 height. But that is not the case.

I think it MIGHT be doing something like this: say your estimatedHeightForRowAtIndexPath value is 150. It is sometimes using 150 for rows that (in fact() prove to be that size or less, but sometimes it goes for the real size from heightForRowAtIndexPath.

On the other hand, if you put in a value for estimatedHeightForRowAtIndexPath that is smaller than will ever actually exist (say 100 in my example) it pretty much "utterly doesn't work" you just get what can only seem to be random heights on the cells.

very high cells seem to work correctly, perhaps something like "if the height from heightForRowAtIndexPath is double the estimated, then it does use the real height"

To be clear, it seems that it never makes a cell too small, but it often makes them too big.

To be clear, I am not using autolayout, it's the type of cell you just have to build. (I'm afraid I have no idea how this goes with autolayout.) This is Xcode5/iOS7+ only.

Answer

Timothy Moose picture Timothy Moose · Dec 5, 2013

Updated Answer

After further investigation, it turns out "it simply requires Auto Layout" is incorrect. It was my sample code that required Auto Layout. I made a slight modification in DynamicHeightCell and it now works with or without Auto Layout.

Original Answer

It simply requires Auto Layout. Not surprising, really, but should absolutely be documented.

Here is a working project demonstrating tableView:estimatedHeightForRowAtIndexPath: working correctly with Auto Layout. If you turn off Auto Layout in the storyboard, it behaves as you've described.

Estimated Row Height Demo