天天看點

iOS Self-Sizing優化

前言

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