相信很多朋友都深有體會,tableViewCell
的高度計算的總是不盡人意
很多時候我們在項目中的cell
會是多種多樣的,當cell
中含有高度不固定的文本label
或textView
時怎么辦
這里先列舉幾個之前的例子:
示例 : One
小白一點的朋友們會發現當我們在cell
中進行高度計算然后return
高度,再在控制器中調用是不可取的,原因在于tableView
的代理方法heightForRowAtIndexPath
會在cellForRowAtIndexPath
之前調用
這個時候cell
還未創建,可能會導致程序的crash
, 調用類似于下面這種形式:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BaseModelCell *cell = [tableView cellForRowAtIndexPath:indexPath];
return [cell cellHeight];
}
示例 : Two
那cell
中不行,我們就在model
里賦值好了,很多時候我們的高度計算會在model
中長這個樣子:
-(CGFloat)cellHeight{
UIFont *currentFont = [ThreePicModel currentFont];
CGRect labelrect = [self.title boundingRectWithSize:Size(WidthScale_IOS6(316), MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingTruncatesLastVisibleLine attributes:@{NSFontAttributeName:currentFont} context:nil];
if (iPhone5 || iPhone4) {
return labelrect.size.height+HeightScale_IOS6(170);
}else{
//計算出自適應的高度
return labelrect.size.height+HeightScale_IOS6(155);
}
}
然后在控制器中調用:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BaseModel *model = self.dataModelAry[indexPath.section];
return model.cellHeight;
}
當然,這種方法是可行的,只要判斷做的足夠多,我們的cell
呈現出來也是可以接受的,但是很多coder門已經厭倦了boundingRectWithSize
這個方法了,工作了的朋友估計也會遇到iOS8
系統下boundingRectWithSize
這個方法有時會導致crash
示例 : Three
我們還可以判斷版本用創建方法計算,類似這個樣子:
UILabel *textLabel = [[UILabel alloc]init];
textLabel.font = [UIFont systemFontOfSize:14];
textLabel.text = [self.user_id stringByAppendingString:[NSString stringWithFormat:@":%@",self.comment]];
textLabel.numberOfLines = 0;//根據最大行數需求來設置
textLabel.lineBreakMode = NSLineBreakByTruncatingTail;
CGSize maximumLabelSize = CGSizeMake(Screen_width - 88, MAXFLOAT);//labelsize的最大值
CGSize finalSize = [textLabel sizeThatFits:maximumLabelSize];
return finalSize.height;
coder們別噴我,我當年用過這個辦法進行高度計算,而且我驗證過,此方法計算出的高度比boundingRectWithSize
計算出來的高度更貼切
好啦~我知道致命的問題,這種方法,循環創建,什么工程也不會允許這么愚蠢的方法...
示例 : Four
那么還有什么方法呢?在github上我發現了這樣一個庫(喜歡鉆研的人士可以傳送門去瞧瞧):
一看簡介著實嚇了我一條 7000+
的star
簡直要媲美我大MJ
了,當然網上有說利用這個庫實現高度自適應是最屌的,我也覺得很厲害,下面開啟傳送門(ps
一下有玩爐石
的coder們么),在工程中使用大體是這個樣子的:
- (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];
}];
}
RunLoop
解決iOS 7以下高度問題
,這個庫統統包含,可是我本人總是覺得工程中盡量少用第三方庫,至少我們產品經理總是這樣教育我們,那么還有什么方法呢?
示例 : Five
用Masonry
+ 適配宏
也很爽,配合label
的sizeToFit
瞬間輕松了,但是會發現cell
一般我們都是會用xib
進行創建,很少純代碼,至少我是這樣,那還有沒有更爽的方法了
[self.summaryLabel sizeToFit];
[self.summaryLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(Size(WidthScale_IOS6(28),HeightScale_IOS6(20)));
make.left.offset(space);
make.centerY.equalTo(self.mas_centerY);
}];
示例 : Six
看好了,如果你的項目適配的最低版本是iOS 8.0,那么接下來的兩行代碼將改變所有對于高度的計算:
self.tableView.estimatedRowHeight = 150;//估算高度
self.tableView.rowHeight = UITableViewAutomaticDimension;
tableView
的estimatedRowHeight
這個特性是在iOS 7
以后才存在,貌似在iOS 8
以后才少了許多7
中出現的bug
,比如在7
中你用這個estimatedRowHeight
會導致滾動條的大小處于不穩定的狀態,contentSize
會隨著滾動從估算高度慢慢替換成真實高度,這完全可以通過肉眼看出 (當然如果你的公司不適配7的話,你懂得??)
我們看一下 estimatedRowHeight
官方文檔給的解釋
The estimated height of rows in the table view.
Providing a nonnegative estimate of the height of rows can improve the performance of loading the table view. 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.
When you create a self-sizing table view cell, you need to set this property and use constraints to define the cell’s size.
The default value is 0, which means there is no estimate.
大體意思是針對iOS 8
以后的,接下來是渣渣翻譯
:
當你創建一個self-sizing表視圖單元格時,你需要設置這個屬性并且使用約束來定義單元格的尺寸。默認值為0,這意味著沒有預估高度
OK,文檔很清楚的說明了需要配合約束一起使用,那么我們可以試一下在xib
中創建一個帶Label
的cell
,label
的高度不固定,其他上下左右約束需要約好,將這兩行代碼加入控制器中:
cell
高度已經完美自適應了,值得注意的是,在這兩行代碼加入后,需要注釋掉heightForRowAtIndexPath
因為一旦設置heightForRowAtIndexPath
將不會遵循tableView
的rowHeight
//-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//
//}
另外如果出現高度還是不對的童鞋們,出現下方這種情況:
請在xib
中保證label
的上下左右都有約束,不過有時候label
雖然有約束但是同label
進行約束的對象不固定,例如:
這個label
針對下面View
進行了bottom
但是View
卻沒有對點擊查看有bottom
的約束,(好像沒有說的很明白)
可以用一個方法檢測一下約束,保證xib
是一塊整體,當我們對cell
進行拉伸時:
就會出現這種警告,其實我們是多加了針對點擊查看對上面分割線的約束,雖然這條約束是多余的,但是保證了cell
的高度被固定了起來,這樣當我們再次運行的時候就會看到我們理想中cell
的樣子了,當然其實tableView
的rowHeight
默認就是UITableViewAutomaticDimension
,所以我們只要預估一下高度,并且約束好就可以達到高度的自適應了.
好了,這種方法是我一直在用的,避免了繁瑣的高度計算,如果coder們有更好的提議,請評論
或私信
我,覺得有用的請點個贊吧~