I have a table view with the potential for each cell to have its own height, thus isn\'t suitable to use rowHeight
. Instead, right now I\'m using let indexSet
In iOS 13.5.1:
I have a tableView which contains 4 types of cells , all off them having different and dynamic heights. I have followed the accepted solution here, but to solve jumping effect I need to add more when reloading table view:
From accepted answer I have added below code: Declare this variable
var allCellHeights = [IndexPath : CGFloat]()
Then add 2 methods:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.allCellHeights[indexPath] = cell.frame.size.height
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return self.allCellHeights[indexPath] ?? UITableView.automaticDimension
}
Now the extra code I have to add when reloading tableview:
let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)
also check this answer : reloadData() of UITableView with Dynamic cell heights causes jumpy scrolling
This behavior appears to be a bug, if for no other reason than it's no longer reproducible on iOS 9. I'm sure that's not much consolation.
The issue primarily derives from having an inaccurate estimate, like @NickCatib said. The best you can do on iOS 8 is to improve the estimation. A technique many have recommended is to cache heights in willDisplayCell
and use them on subsequent calls to estimatedRowHeightAtIndexPath
.
You might be able to mitigate the behavior by not doing anything to get UITableView
to discard its caches, like by modifying the content in a cell directly using cellForRowAtIndexPath
rather than using reloading if it's onscreen. However, that won't help if you actually need to change the height of the cell.
I'm afraid to say the bug can't be easily be fixed within a table view, as you don't have control over the layout. The bug can be more easily worked around in a subclass UICollectionViewFlowLayout
by changing the contentOffsetAdjustment
during invalidation, although that might not be terribly easy.
I was facing the same problem, my table works fine until the tableview reloads. So i found a solution, use only rowHeight not estimated height. Also if you have different height. So please provide the complete code so i will provide a solution. I have a cell which like instagram page. I am passing calculated height in heightforrow method which work fine. But estimated height not works fine in that situation. If you use below code, it works fine. Please try.
self.tableView.rowHeight = 75 //it will be your dynamic height
//self.tableView.estimatedRowHeight = 75
If you confuse to calculate the height for row for each cell, just post the sample i will provide the solution. If i can Thanks
Uh... this is kind of hard issue to deal with.
Let's take a look at facebook. They had this same issue with their timeline, and they ended up doing it in some kind of web view.
I had a similar issue with some kind of timeline, used automatic row height and had that issue. First thing to resolve it was to set estimatedHeight
as close as possible to average cell height. That is pretty hard to deal with since you may have text (height 50) or images + text ( height 1500). Next thing to do with improving this was implementing estimatedHeight forIndexPath
which basicly return different estimated height for different indexPaths.
After that there were a lot of other solutions but this was as closest as it can with variable heights (huge differences).
I had this issue too and used a solution from SO which I am unable to find right now. If I do, I will add the link. Here's the solution:
The issue is with table view not having the right estimate for height of rows. To fix it, cache the height initially in willDisplayCell
and next time use that height.
Code
In viewDidLoad:
heightAtIndexPath = [NSMutableDictionary new];
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *height = @(cell.frame.size.height);
[heightAtIndexPath setObject:height forKey:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
if([heightAtIndexPath objectForKey:indexPath]) {
return [[heightAtIndexPath objectForKey:indexPath] floatValue];
} else {
return UITableViewAutomaticDimension;
}
}