我是前言
這篇文章是我和我們團隊最近對 UITableViewCell 利用 AutoLayout 自動高度計算和 UITableView 滑動優化的一個總結。
我們也在維護一個開源的擴展,UITableView+FDTemplateLayoutCell,讓高度計算這個事情變的前所未有的簡單,也受到了很多星星的支持,github鏈接請戳我 (本地下載)
這篇總結你可以讀到:
UITableViewCell高度計算
rowHeight
UITableView是我們再熟悉不過的視圖了,它的 delegate 和 data source 回調不知寫了多少次,也不免遇到 UITableViewCell 高度計算的事。UITableView 詢問 cell 高度有兩種方式。
一種是針對所有 Cell 具有固定高度的情況,通過:
self.tableView.rowHeight = 88;
上面的代碼指定了一個所有 cell 都是 88 高度的 UITableView,對于定高需求的表格,強烈建議使用這種(而非下面的)方式保證不必要的高度計算和調用。rowHeight屬性的默認值是 44,所以一個空的 UITableView 顯示成那個樣子。
另一種方式就是實現 UITableViewDelegate 中的:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // return xxx}
需要注意的是,實現了這個方法后,rowHeight 的設置將無效。所以,這個方法適用于具有多種 cell 高度的 UITableView。
estimatedRowHeight
這個屬性 iOS7 就出現了, 文檔是這么描述它的作用的:
If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.
恩,聽上去蠻靠譜的。我們知道,UITableView 是個 UIScrollView,就像平時使用 UIScrollView 一樣,加載時指定 contentSize 后它才能根據自己的 bounds、contentInset、contentOffset 等屬性共同決定是否可以滑動以及滾動條的長度。而 UITableView 在一開始并不知道自己會被填充多少內容,于是詢問 data source 個數和創建 cell,同時詢問 delegate 這些 cell 應該顯示的高度,這就造成它在加載的時候浪費了多余的計算在屏幕外邊的 cell 上。和上面的 rowHeight 很類似,設置這個估算高度有兩種方法:
self.tableView.estimatedRowHeight = 88;// or- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { // return xxx}
有所不同的是,即使面對種類不同的 cell,我們依然可以使用簡單的 estimatedRowHeight 屬性賦值,只要整體估算值接近就可以,比如大概有一半 cell 高度是 44, 一半 cell 高度是 88, 那就可以估算一個 66,基本符合預期。
說完了估算高度的基本使用,可以開始吐槽了:
iOS8 self-sizing cell
具有動態高度內容的 cell 一直是個頭疼的問題,比如聊天氣泡的 cell, frame 布局時代通常是用數據內容反算高度:
CGFloat height = textHeightWithFont() + imageHeight + topMargin + bottomMargin + ...;
供 UITableViewDelegate 調用時很可能是個 cell 的類方法:
@interface BubbleCell : UITableViewCell+ (CGFloat)heightWithEntity:(id)entity;@end
各種魔法 margin 加上耦合了屏幕寬度。
AutoLayout 時代好了不少,提供了-systemLayoutSizeFittingSize:的 API,在 contentView 中設置約束后,就能計算出準確的值;缺點是計算速度肯定沒有手算快,而且這是個實例方法,需要維護專門為計算高度而生的 template layout cell,它還要求使用者對約束設置的比較熟練,要保證 contentView 內部上下左右所有方向都有約束支撐,設置不合理的話計算的高度就成了0。
這里還不得不提到一個 UILabel 的蛋疼問題,當 UILabel 行數大于0時,需要指定 preferredMaxLayoutWidth 后它才知道自己什么時候該折行。這是個“雞生蛋蛋生雞”的問題,因為 UILabel 需要知道 superview 的寬度才能折行,而 superview 的寬度還依仗著子 view 寬度的累加才能確定。這個問題好像到 iOS8 才能夠自動解決(不過我們找到了解決方案)
回到正題,iOS8 WWDC 中推出了 self-sizing cell 的概念,旨在讓 cell 自己負責自己的高度計算,使用 frame layout 和 auto layout 都可以享受到:
這個特性首先要求是 iOS8,要是最低支持的系統版本小于8的話,還得針對老版本單寫套老式的算高( 主站蜘蛛池模板: 张北县| 淅川县| 中西区| 四川省| 万源市| 新巴尔虎右旗| 庆元县| 辽宁省| 紫云| 马公市| 陈巴尔虎旗| 鹰潭市| 台州市| 特克斯县| 札达县| 敦化市| 东台市| 澜沧| 界首市| 东兰县| 邢台县| 临桂县| 永德县| 乌鲁木齐县| 宁安市| 迭部县| 龙井市| 新乐市| 玛纳斯县| 永昌县| 田林县| 玉环县| 城口县| 安徽省| 贵州省| 万荣县| 宽甸| 屏东县| 辛集市| 大宁县| 高陵县|