On iOS 11, UITableView uses estimated row height as default.
It leads to unpredictable behaviors when inserting/reloading or deleting rows because the UITableView has a wrong content size most of the time:
To avoid too many layout calculations, the tableView asks heightForRow
only for each cellForRow
call and remembers it (in normal mode, the tableView asks heightForRow
for all the indexPaths of the tableView). The rest of the cells has a height equal to the estimatedRowHeight
value until their corresponding cellForRow
is called .
// estimatedRowHeight mode
contentSize.height = numberOfRowsNotYetOnScreen * estimatedRowHeight + numberOfRowsDisplayedAtLeastOnce * heightOfRow
// normal mode
contentSize.height = heightOfRow * numberOfCells
I guess UIKit struggles to animate correctly the changes because of this trick.
One solution is to disable the estimatedRowHeight
mode by setting estimatedRowHeight to 0 and implementing heightForRow
for each of your cells.
Of course, if your cells have dynamic heights (with onerous layout calculations most of time so you used estimatedRowHeight
for a good reason), you would have to find a way to reproduce the estimatedRowHeight
optimization without compromising the contentSize of your tableView. Take a look at AsyncDisplayKit or UITableView-FDTemplateLayoutCell.
Another solution is to try to find a estimatedRowHeight
which suits well. Since iOS 10, you can also try to use UITableView.automaticDimension
. UIKit will find a value for you:
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension
On iOS 11, it's already the default value.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…