UITableView一直是咱們app中使用頻率最高的控件。UITableViewCell的算高問題也一直是一個老生常談的問題。咱們通常算高都是將cell中得各個控件的高度計算出來,而後給外界拋出一個接口,用來獲取cell高度。若是cell是定高還好,若是是變高,咱們還要計算文字圖片的高度,每個不一樣的cell 都有一大段算高的代碼,並且tableview返回高度的代理方法,老是很頻繁的調用,咱們還要注意不要在主線程使用過於複雜的算法以避免阻塞主線程。有時候,這些事情會搞得咱們不勝其煩,咱們老是把焦點放在這些地方,它耗費了咱們大量的時間,咱們急須要一種解決方案,能夠將咱們從其中解脫出來。git
蘋果已經注意到了這個問題,因此它在IOS7新增長了一個APIgithub
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
有人對這個方法有印象嗎?這是IOS7以後新添加的方法。解釋這個方法以前,須要先了解tableView的算高機制。算法
咱們之前一般使用heightForRowAtIndexPath方法返回對應cell高度,tableView在渲染以前都要調用這個方法來獲取各個cell的高度,而後獲得tableView的總高度,這意味在顯示tableView以前須要進行大量的高度計算。注意這不是一屏,是計算全部數據的高度,而且是在主線程,頗有可能會形成加載過慢,卡頓等現象。有人問爲何不能等頁面滑動到某個 cell 的時候,再計算高度呢?答案就是,tableView有一個小的ScrollIndicator滾動條,高度是用來肯定滾動條的大小和位置的。緩存
estimatedHeightForRowAtIndexPath這個方法的意思就是返回一個cell 高度的估計值,這樣tableView就直接取估值用來肯定滾動條的信息而不須要調用屢次算高的代理方法,這樣就能夠大幅度提升tableView的加載速度。app
須要注意的是:1.它是IOS7以後纔有的API。2.若是你的業務需求須要你一開始使用到tableView的contentSize或者contentOffset,那麼請慎用。
ide
如今有一種方案可讓咱們不用費勁腦力去計算使人厭煩的行高,就是從autoLayout上面獲取咱們想要的cell高度。佈局
在IOS8 WWDC上面蘋果提出了一個概念self-sizing cell ,可讓cell根據內容自我適應高度。開啓的方法就是開啓上面提到的估算高度。spa
tableView.estimatedRowHeight = 44;
這樣一句話就能夠了。線程
爲何開啓估算行高才能使用self-sizing?我猜多是用autoLayout計算行高,會耗費大量的CPU時間,不開啓估算行高,可能開始會一會兒把主線程卡住,這樣體驗很是的很差。並且IOS8的tableView的滾動機制與以往不一樣,它沒有作行高緩存,當你滾動的時候,它會頻繁調用計算行高的代理方法。代理
惋惜蘋果的節奏老是慢那麼一拍,咱們在IOS7及更早的版本就沒法使用self-sizing。可是通常的app都要求適配IOS7或者更早的版本,這樣就須要咱們本身去處理一下咱們首先要用cell的contentView調用systemLayoutSizeFittingSize:方法計算出cell所需的高度是多少。使用UILayoutFittingCompressedSize參數能夠獲得適合cell中全部內容所需的最小尺寸。而後其高度就能夠做tableView:heightForRowAtIndexPath:方法的返回值。
在當我準備寫一套autoLayout自動算高的擴展時,我發現了有人爲咱們寫好了它,因而我決定再也不重複造輪子了。
爲咱們提供了一個自動計算行高,而且運行流暢(能夠緩存行高),並且最低支持IOS6的一站式解決方案。具體的原理你們能夠看它的源碼。我在這裏說一下大體的使用方法。
1.首先你的layout須要設置正確。在UITableViewCell子類中,添加布局約束,使得cell子視圖的邊緣固定(pin)到cell的contentView的邊緣(最重要的是要有頂部和底部的邊距約束條件)。注意:不要將子視圖的邊距約束固定到cell自己上了,只能固定到cell的contentView上, 確保每一個子視圖垂直方向上的內容壓縮阻力(compression resistance)和吸附性約束(hugging constraints)沒有被你添加的更高優先級的約束條件覆蓋,讓這些子視圖的固有內容尺寸(intrinsic content size)來驅動contentView的高度。(看不懂推薦這本書 《iOS Auto Layout開發祕籍》)
2.在tableView中註冊你的cell
[tableView registerNib:[UINib nibWithNibName:@"Cell" bundle:nil] forCellReuseIdentifier:@「Cell"]; 或者 [tableView registerClass:[Cell class] forCellReuseIdentifier:@「Cell」];
3.改寫tableView的高度代理方法,代碼以下
#import <UITableView+FDTemplateLayoutCell.h> - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) { // 配置 cell 的數據源,和 "cellForRow" 乾的事一致,好比: cell.entity = self.feedEntities[indexPath.row]; }]; }
enjoy it