1. 程式人生 > >iOS-談一談自適應Cell的高度快取

iOS-談一談自適應Cell的高度快取

目錄

  • 系統如何計算的自適應高度?

  • 系統計算的行高會不會被快取?

  • 如何快取?

前幾天讀文件的時候發現一對方法

- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize NS_AVAILABLE_IOS(6_0); 
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority NS_AVAILABLE_IOS(8_0);

具體可以參閱《iOS文件補完計劃–UIView》中的相關解釋。

簡而言之這兩個方法會:

返回Auto Layout後內容高度

並且、我們都知道UITableView、如果設定成rowHeight = UITableViewAutomaticDimension的話。cell的高度將由系統通過Auto Layout自動計算。

  • 系統如何計算的自適應高度?

而這個計算、是否通過上面兩個方法呢?

經過試驗、答案是肯定的。

系統呼叫的正是- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority NS_AVAILABLE_IOS(8_0);

這個方法。

  • 系統計算的行高會不會被快取?

經過試驗、答案是否定的。也就是系統不會快取計算過的行高

這裡有兩個能夠讓Cell自適應的方式

  1. 對UITableView進行設定

tableView.rowHeight = UITableViewAutomaticDimension
  1. 通過代理返回

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

結果是無論使用哪個方法、在每次Cell即將被展示的時候、都會自動呼叫上述的systemLayoutSizeFittingSize方法。

兩個關鍵的步驟是:

  1. 通過cellForRowAtIndexPath對某個Cell進行配置 而我們在這一步已經將Cell的內容配置完畢了

  2. 通過[UITableView _heightForCell:atIndexPath:]計算Cell高度 而內部則呼叫systemLayoutSizeFittingSize獲取具體的高度。

  • 如何快取?

經過以上兩個探索、我們已經知道Cell通過systemLayoutSizeFittingSize高度、並且不會被快取。

那麼、我們需要做的就是自己計算高度、並且快取。直接貼一下程式碼:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    BSQuestionsModel * model = _dataArray[indexPath.section];
    return model.cell_height?:UITableViewAutomaticDimension;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    BSQuestionsModel * model = _dataArray[indexPath.section];
    BSQuestionsTableViewCell * cell = [BSQuestionsTableViewCell cellForTableView:tableView model:model];

    //高度快取
    CGFloat height = [cell systemLayoutSizeFittingSize:CGSizeMake(tableView.frame.size.width, 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel].height;
    model.cell_height = height;

    return cell;
}

這樣、cell在進行過一次高度計算之後。就不需要在計算第二次了

然後關於上面的程式碼有幾點需要說:

  1. 為什麼在cellForRowAtIndexPath裡做快取 最開始我們已經談過了、cellForRowAtIndexPath的呼叫在獲取自動佈局的高度之前、這樣也能避免重複取用對應位置的Cell。

而返回的UITableViewAutomaticDimension主要是為了怕低版本有問題(雖然我感覺應該不會)。

  1. 為什麼用systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority 網上很多帖子都這樣寫:

[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]

但是在我這不太好用、因為我cell內部有一些優先順序的設定。

所以、我乾脆和系統呼叫的方式一樣。

  1. 非同步計算 是的、我們又可以非同步計算了。雖然我沒寫、因為我現在得抓緊碼頁面~

關於一些舊帖子

我搜到的都是14/15年的帖子、和現在的情況感覺還是有出入的。

  1. cell.contentView取出的高度要+1 網上對+1的解釋是、cellcell.contentView要搞出1個單位。還附上了兩張圖。

但是現在、cell是比cell.contentView高出0.5(0.5也不一定準確、xib上有四捨五入的嫌疑)、而不是1。

  1. cell還是用cell.contentView 我在網上搜了很多帖子、都說要使用cell.contentView 但是我用cell一樣可以獲取高度。所以用cell唄~

最後

本文主要是自己的學習與總結。如果文記憶體在紕漏、萬望留言斧正。如果願意補充以及不吝賜教小弟會更加感激。

作者:kirito_song