Why does my UITableView “jump” when inserting or removing a row?

后端 未结 10 1201
小蘑菇
小蘑菇 2020-12-05 10:21

(Happy to accept an answer in Swift or Objective-C)

My table view has a few sections, and when a button is pressed, I want to insert a row at the end of section 0.

10条回答
  •  情书的邮戳
    2020-12-05 10:37

    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
    

    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.

提交回复
热议问题