前言
在 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
}
}