UITableview是iOS開發(fā)中使用最頻繁的一個控件,在實際開發(fā)中,我們經常需要定制cell,讓cell顯示圖片、文字等。由于cell包含的圖片和文字是根據(jù)服務器返回的數(shù)據(jù)進行填充的,這就導致cell包含的內容的高度是不定的。
1、iOS8的自動計算機制,需要autolayout(適用iOS8之后系統(tǒng))2、iOS6之后系統(tǒng)API結合autolayout進行計算(適用于iOS6之后的系統(tǒng))3、手動計算(適用于iOS6之后的系統(tǒng))4、借助于第三方框架自動計算(適用于iOS6之后的系統(tǒng))
 //viewController.m文件  //===========================  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{      static TableViewCell *Cell;      static dispatch_once_t onceToken;      //必須使用dispatch_once,保證只會從緩存池中取一個cell用于高度計算,其他的cell高度都是用這個cell的高度。不然每次都從緩存池中取出來不同的cell,導致高度計算出問題      dispatch_once(&onceToken, ^{          Cell = [tableView dequeueReusableCellWithIdentifier:CellId];      });       TableViewModel *model = self.modelArray[indexPath.row];      Cell.model = model;      // 根據(jù)當前數(shù)據(jù),計算Cell的高度,注意+1是contentview和cell之間的分割線高度      model.cellHeight = [Cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height +1.0f;     return model.cellHeight;  }    //實現(xiàn)該方法后,tableview就不會一次性調用完所有cell的高度,有些不在可見范圍的cell是不需要一開始就知道高度的。當然,estimatedHeightForRowAtIndexPath方法調用頻率就會非常高,所以我們盡量返回一個比較接近實際結果的固定值以提高性能.  - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {      return 112.0f;  }  該方法實現(xiàn)效果和方法一相同
//viewController.m文件  //===========================  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{      static TableViewCell *Cell;      static dispatch_once_t onceToken;      //必須使用dispatch_once,保證只會從緩存池中取一個cell用于高度計算,其他的cell高度都是用這個cell的高度。不然每次都從緩存池中取出來不同的cell,導致高度計算出問題      dispatch_once(&onceToken, ^{          Cell = [tableView dequeueReusableCellWithIdentifier:CellId];      });       TableViewModel *model = self.modelArray[indexPath.row];      Cell.model = model;      // 根據(jù)當前數(shù)據(jù),計算Cell的高度,注意+1是contentview和cell之間的分割線高度      model.cellHeight = [Cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height +1.0f;     return model.cellHeight;  }    //實現(xiàn)該方法后,tableview就不會一次性調用完所有cell的高度,有些不在可見范圍的cell是不需要一開始就知道高度的。當然,estimatedHeightForRowAtIndexPath方法調用頻率就會非常高,所以我們盡量返回一個比較接近實際結果的固定值以提高性能.  - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {      return 112.0f;  }  該方法實現(xiàn)效果和方法一相同方法3、手動計算
該方法需要手動計算垂直高度上每個控件的高度,然后相加得出cell的高度。這種方法最繁瑣,但是也是最精確的,也是最可控的。使用這個方法,可以不需要使用autolayout設置約束,直接使用frame設置每個控件的位置。但是為了方便,我這里還是使用autolayout設置控件的約束和位置。
因為需要確切的知道每個控件的高度,所以這里image的高度必須是固定的,這樣才可以進行cell的高度計算修改如下
![]()
修改的代碼如下:
[objc] view plain copy 
 //TableViewModel.m文件  //===============================  #import "TableViewModel.h"    @implementation TableViewModel    //方法3代碼  - (CGFloat)cellHeight{      // 文字的最大尺寸(設置內容label的最大size,這樣才可以計算label的實際高度,需要設置最大寬度,但是最大高度不需要設置,只需要設置為最大浮點值即可),53為內容label到cell左邊的距離      CGSize maxSize = CGSizeMake([UIScreen mainScreen].bounds.size.width - 53, MAXFLOAT);        // 計算內容label的高度      CGFloat textH = [self.userContentString boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size.height;        /*      昵稱label和cell的頂部為0      17為昵稱label的高度      8.5為昵稱label和內容label的間距      textH為內容label的高度      304為內容image的高度      */      _cellHeight = 0 + 17 + 8.5 + 8 +textH + 304;        return _cellHeight;  }  [objc] view%20plain copy
//TableViewModel.m文件  //===============================  #import "TableViewModel.h"    @implementation TableViewModel    //方法3代碼  - (CGFloat)cellHeight{      // 文字的最大尺寸(設置內容label的最大size,這樣才可以計算label的實際高度,需要設置最大寬度,但是最大高度不需要設置,只需要設置為最大浮點值即可),53為內容label到cell左邊的距離      CGSize maxSize = CGSizeMake([UIScreen mainScreen].bounds.size.width - 53, MAXFLOAT);        // 計算內容label的高度      CGFloat textH = [self.userContentString boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size.height;        /*      昵稱label和cell的頂部為0      17為昵稱label的高度      8.5為昵稱label和內容label的間距      textH為內容label的高度      304為內容image的高度      */      _cellHeight = 0 + 17 + 8.5 + 8 +textH + 304;        return _cellHeight;  }  [objc] view%20plain copy ![在CODE上查看代碼片]()
 //ViewController.m文件  //==========================    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{   //方法3代碼     TableViewModel *model =  self.modelArray[indexPath.row];      return model.cellHeight;  }
//ViewController.m文件  //==========================    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{   //方法3代碼     TableViewModel *model =  self.modelArray[indexPath.row];      return model.cellHeight;  }  方法四、使用第三方框架
這是國內的一個大神寫的框架,可以一行代碼就實現(xiàn)cell的高度自動計算。同時還能實現(xiàn)緩存高度,最低兼容版本為iOS6。實現(xiàn)代碼就不寫了,非常簡單
具體看這篇文章:《優(yōu)化UITableViewCell高度計算的那些事》
這里啰嗦兩點,也是自己踩過的坑:
1、在博主的文字里面提到使用的時候直接使用如下代碼即可:
[objc] view%20plain copy ![在CODE上查看代碼片]()
 #import <UITableView+FDTemplateLayoutCell.h>  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {      return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) {          // 配置 cell 的數(shù)據(jù)源,和 "cellForRow" 干的事一致,比如:          cell.entity = self.feedEntities[indexPath.row];      }];  }
#import <UITableView+FDTemplateLayoutCell.h>  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {      return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) {          // 配置 cell 的數(shù)據(jù)源,和 "cellForRow" 干的事一致,比如:          cell.entity = self.feedEntities[indexPath.row];      }];  }  一定要把上面的id%20cell,換成自己的cell類,比如我的就是WSTableViewCell%20*cell。算是一個小坑吧。
2、很多人肯定吃過self-sizing-cell的虧,覺得我上面都設置對了,為什么就是算不出來高度呢?
要滿足self-sizing-cell,必須滿足兩點:
你的cell里面的控件必須在上下左右四個方向都有約束到cell的四個邊。如下圖:![]()
*約束一定要是控件和cell的contentView邊緣之間的約束,而不是控件和cell邊緣的之間的約束。
因為設計給的圖,cell內部的控件和cell的距離是到cell邊緣的距離,然后我就發(fā)現(xiàn)怎么都不能進行高度自動計算,所有的cell全部疊在一起了。被這個坑了很久,一直找不出來原因。另外cell的邊緣和cell的contentView的邊緣相差8pt。
錯誤設置:
ReplayCell是cell的名字

正確設置:
superView是cell的contentView

總結:
上面四種方法各有優(yōu)缺點,如果你的App最低兼容版本是iOS8,那請毫不猶豫的選擇方法一的系統(tǒng)方法吧,高效簡潔。
如果你需要最低兼容iOS6,可以從其他三個方法中選一個,建議使用方法四的第三方框架,高效強大。
所有的代碼都放在了Github上面,小伙伴們可以參考下。
地址如下:https://github.com/XiMu-Demo/Blog-Demo/tree/master/calculateCellHeight百度 開源的一個自動計算Cell 高度 第三方UITableView-FDTemplateLayoutCell-masterhttp://blog.sunnyxx.com/2015/05/17/cell-height-calculation/