前言
在 iOS 11之后,UITableView默认开启了Self-Sizing。利用Self-Sizing技术,我们可以不需要实现heightForRowAt方法。但Self-Sizing可能会引起UITableView的闪烁问题,需要做一些优化处理。
我们知道:在 iOS 11之后,UITableView默认开启了Self-Sizing。利用Self-Sizing技术,我们不需要实现heightForRowAt方法,系统通过AutoLayout约束自动计算cell高度并绘制显示,这是一项非常不错的改进。但Self-Sizing可能会引起UITableView的闪烁问题,需要做一些优化处理。
开启Self-Sizing
iOS 10及之前版本需要配置:
tableView.estimatedRowHeight = 100.0 tableView.rowHeight = UITableView.automaticDimension
iOS 11之后仅需要配置:
tableView.rowHeight = UITableView.automaticDimension
在自定义的UITableViewCell中使用AutoLayout,不要实现heightForRowAt方法,即可使用UITableView的Self-Sizing。
同时,tableFooterView和tableHeaderView也是支持Self-Sizing的,不过需要通过systemLayoutSizeFitting的方法先获取其高度。
开启Self-Sizing 页面闪烁问题
当使用Self-Sizing滑动UITableView多次之后,执行reloadRows或reload很可能出现页面闪烁问题。
原因是即使使用了Self-Sizing技术,iOS系统还是要进行预估cell高度的操作,它会影响到滚动条的高度,如果提供的预估高度和实际cell的高度差别较大,就会带来闪烁问题。
一个比较好的改进方法是:
- 定义存储预估高度的map:
private var heightMap = [Int: CGFloat]()
- 增加实现estimatedHeightForRowAt和willDisplay的逻辑,分别获取和设置heightMap,即可解决UITableView闪烁问题。
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { if let value = heightMap[indexPath.row] { return value } else { return 100.0 } } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { let key = indexPath.row if let _ = heightMap[key] { } else { heightMap[key] = cell.frame.size.height } }