Is there a way to update the height of a single UITableViewCell, without recalculating the height for every cell?
As noted, reloadRowsAtIndexPaths:withRowAnimation:
will only cause the table view to ask its UITableViewDataSource
for a new cell view but won't ask the UITableViewDelegate
for an updated cell height.
Unfortunately the height will only be refreshed by calling:
[tableView beginUpdates];
[tableView endUpdates];
Even without any change between the two calls.
If your algorithm to calculate heights is too time consuming maybe you should cache those values. Something like:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = [self cachedHeightForIndexPath:indexPath];
// Not cached ?
if (height < 0)
{
height = [self heightForIndexPath:indexPath];
[self setCachedHeight:height
forIndexPath:indexPath];
}
return height;
}
And making sure to reset those heights to -1
when the contents change or at init time.
Edit:
Also if you want to delay height calculation as much as possible (until they are scrolled to) you should try implementing this (iOS 7+ only):
@property (nonatomic) CGFloat estimatedRowHeight
Providing a nonnegative estimate of the height of rows can improve the performance of loading the table view. If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.
The default value is 0, which means there is no estimate.
This bug has been fixed in iOS 7.1.
In iOS 7.0, there doesn't seem to be any way around this problem. Calling [self.tableView endUpdates]
causes heightForRowAtIndexPath:
to be called for every cell in the table.
However, in iOS 7.1, calling [self.tableView endUpdates]
causes heightForRowAtIndexPath:
to be called for visible cells, and estimatedHeightForRowAtIndexPath:
to be called for non-visible cells.
Variable row heights have a very negative impact on your table view performance. You are talking about web content that is displayed in some of the cells. If we are not talking about thousands of rows, thinking about implementing your solution with a UIWebView instead of a UITableView might be worth considering. We had a similar situation and went with a UIWebView with custom generated HTML markup and it worked beautifully. As you probably know, you have a nasty asynchronous problem when you have a dynamic cell with web content:
- After setting the content of the cell you have to
- wait until the web view in the cell is done rendering the web content,
- then you have to go into the UIWebView and - using JavaScript - ask the HTML document how high it is
- and THEN update the height of the UITableViewCell.
No fun at all and lots of jumping and jittering for the user.
If you do have to go with a UITableView, definitely cache the calculated row heights. That way it will be cheap to return them in heightForRowAtIndexPath:
. Instead of telling the UITableView what to do, just make your data source fast.
Is there a way? The answer is no.
You can only use heightForRowAtIndexPath for this. So all you can do is make this as inexpensive as possible by for example keeping an NSmutableArray of your cell heights in your data model.
I had a similar issue(jumping scroll of the tableview on any change) because I had
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 500; }
commenting the entire function helped.