天天看點

UITableViewcell autolayout下動态高度

項目中最常用的一個UI就是UITableView了,iOS7、8進一步優化了複用機制,用起來相當爽。配合Autolayout,适配工作減輕了很多。

以前做适配工作都是在heightForRow裡邊先計算出來Cell的高度,然後再CellForRow寫适配代碼。工作量雖然不是很大,但是很繁瑣。

相對于這種寫法,如果減去計算height這步,工作量自然減少很多。首先給出一種我媳婦給提供的方法,這是她做聊天UI時由于過度計算而怒創的方法

UITableViewcell autolayout下動态高度

,當時我看到就震驚了,之後我就一直用這個方法

UITableViewcell autolayout下動态高度

UITableViewcell autolayout下動态高度

使用這中方法即可省重複計算frame的操作,計算一次布局即可。

現在IOS7、8都出來這麼久了,autolayout也炒的很熱,現在看了下确實友善了很多。比我在iOS6友善多了。

前兩天看了下autolayout,現在結合tableviewcell試試效果,看了幾個demo,發現iOS7跟iOS8不一樣,iOS8更加簡單。

第一、iOS7 tableviewcell + autolayout

使用storyboard簡單建立一個工程,并添加如下限制(不熟悉限制添加方法的可參考我之前的部落格autolayout)

UITableViewcell autolayout下動态高度

關聯工程檔案,Cell連線,複用辨別符等(不熟悉,可參考我之前的部落格):

UITableViewcell autolayout下動态高度
UITableViewcell autolayout下動态高度

重頭戲來了,代碼中改如何修改:

cellForRow依然是我們之前的寫法,指派:

<span style="color:#993399;">- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testCell" forIndexPath:indexPath];
    NSLog(@"cell create...");
    if (!cell) {
        NSLog(@"cell is nil!");
    }
    cell.ts_label.text = self.data[indexPath.row];

    return cell;
}</span>
           

重點在于計算height,修改方法如下:

<span style="color:#993399;">- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TestCell* cell = [tableView dequeueReusableCellWithIdentifier:@"testCell"];

    cell.ts_label.text = self.data[indexPath.row];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"size = %@ %lf",NSStringFromCGSize(size),    cell.ts_label.preferredMaxLayoutWidth
);

    return size.height + 1;
}
</span>
           

有三點需要注意:

第一點:不要在heightForRow使用

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath

你會發現進入了死循環。heightForRow->cellforRow->hei...Row

第二點:使用systemLayoutSizeFittingSize,他會根據限制條件算出來新的size,(是以限制條件一定要準确,很多BUG都是因為限制有問題)

它有兩種參數:

UIKIT_EXTERN const CGSize UILayoutFittingCompressedSize NS_AVAILABLE_IOS(6_0);//緊湊,大小适中的最小尺寸

UIKIT_EXTERN const CGSize UILayoutFittingExpandedSize NS_AVAILABLE_IOS(6_0);//寬松

第三點:新的size計算的是contentview的size,Cell.size.height = content view.size.height+1,記得加上一個分割線的高度。

好的到這裡看看運作效果:

UITableViewcell autolayout下動态高度

咋一看感覺效果實作了,仔細觀察發現label的高度算的不對,第三行label不隻有三行,是以這個size算的不準。

經過研究發現,這個時候需要給label一個寬度值,這樣才能算出來所需要的高度。可以設定label的這個屬性來固定寬度。

// Support for constraint-based layout (auto layout)

// If nonzero, this is used when determining -intrinsicContentSize for multiline labels

@property(nonatomic) CGFloat preferredMaxLayoutWidth NS_AVAILABLE_IOS(6_0);

我們修改heightForRow的方法: 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TestCell* cell = [tableView dequeueReusableCellWithIdentifier:@"testCell"];
    cell.ts_label.preferredMaxLayoutWidth = 260;
    cell.ts_label.text = self.data[indexPath.row];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"size = %@ %lf",NSStringFromCGSize(size),    cell.ts_label.preferredMaxLayoutWidth
);

    return size.height + 1;
}
           

跑起來看看效果:

UITableViewcell autolayout下動态高度

這才像個樣子,哇哈哈。

這個屬性也可以在storyboard中設定:

UITableViewcell autolayout下動态高度

第二、iOS8 tableviewcell + autolayout

iOS7的方法已經簡單很多了,不過iOS8更加簡單:iOS8隻需要兩行代碼加上限制即可完成适配!!

UITableViewcell autolayout下動态高度

有木有很誇張!!

看方法:

<span style="color:#993399;">- (void)viewDidLoad {
</span><span style="color:#663366;">    [super viewDidLoad];
    
    self.data = @[@"hahahahahahahahahahahaha",@"gagagaga",@"lalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalalala",@"wawawawawawawawawawawawawawawawawawawawa",@"papapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapapa",@""];
    self.tableView.estimatedRowHeight = 120;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

}</span>
           
<span style="color:#663366;">- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testCell" forIndexPath:indexPath];
    NSLog(@"cell create...");
    if (!cell) {
        NSLog(@"cell is nil!");
    }
    cell.ts_label.text = self.data[indexPath.row];

    return cell;
}</span>
           

看到沒有,iOS8設定都不需要heightForRow了,隻需要設定下預估高度

<span style="color:#663366;">estimatedRowHeight</span>
           
<span style="color:#663366;"></span><pre name="code" class="objc"><span style="color:#663366;">rowHeight = UITableViewAutomaticDimension</span>
           

iOS7優化了tableview,擷取Cell高度不再是一次性全部加載heightForRow,然後再生成Cell。而是先調用:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

等Cell真正要呈現的時候在調用heightForRow。

真實的效果呢

UITableViewcell autolayout下動态高度

高端大氣上檔次啊,哇哈哈。看看其他機型

UITableViewcell autolayout下動态高度

哈哈,就是這麼簡單,Cell就是配好了!!!

總結一下:iOS7需要注意preferredMaxLayoutWidth的設定,iOS8需要設定estimatedRowHeight、rowHeight = UITableViewAutomaticDimension。更加注意的是限制的準确!!!

UITableViewcell autolayout下動态高度

繼續閱讀