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自適應的方式
-
對UITableView進行設定
tableView.rowHeight = UITableViewAutomaticDimension
-
通過代理返回
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewAutomaticDimension; }
結果是無論使用哪個方法、在每次Cell即將被展示的時候、都會自動呼叫上述的systemLayoutSizeFittingSize
方法。
兩個關鍵的步驟是:
-
通過
cellForRowAtIndexPath
對某個Cell進行配置 而我們在這一步已經將Cell的內容配置完畢了 -
通過
[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在進行過一次高度計算之後。就不需要在計算第二次了
然後關於上面的程式碼有幾點需要說:
-
為什麼在
cellForRowAtIndexPath
裡做快取 最開始我們已經談過了、cellForRowAtIndexPath
的呼叫在獲取自動佈局的高度之前、這樣也能避免重複取用對應位置的Cell。
而返回的UITableViewAutomaticDimension
主要是為了怕低版本有問題(雖然我感覺應該不會)。
-
為什麼用
systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority
網上很多帖子都這樣寫:
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]
但是在我這不太好用、因為我cell內部有一些優先順序的設定。
所以、我乾脆和系統呼叫的方式一樣。
-
非同步計算 是的、我們又可以非同步計算了。雖然我沒寫、因為我現在得抓緊碼頁面~
關於一些舊帖子
我搜到的都是14/15年的帖子、和現在的情況感覺還是有出入的。
-
cell.contentView
取出的高度要+1 網上對+1的解釋是、cell
比cell.contentView
要搞出1個單位。還附上了兩張圖。
但是現在、cell是比cell.contentView高出0.5(0.5也不一定準確、xib上有四捨五入的嫌疑)、而不是1。
-
用
cell
還是用cell.contentView
我在網上搜了很多帖子、都說要使用cell.contentView 但是我用cell一樣可以獲取高度。所以用cell唄~
最後
本文主要是自己的學習與總結。如果文記憶體在紕漏、萬望留言斧正。如果願意補充以及不吝賜教小弟會更加感激。
作者:kirito_song