IOS 6.0+ Autolayout — UITableViewCell 高度調整

要實現的效果

要求:

通常titleLabel 僅顯示一行標題,高度爲固定。ios

imageview 大小也爲固定。git

detailLabel 寬度固定,但高度根據文本動態調整。 github

cell 底部拒imageview 的底部以及detailLabel 底部高度都是大於等於20。xcode

當detailLabel文字不多時,cell底部拒imageview底部維持20,這時detaillabel底部距cell 底部大於20. iphone

當detailLabel文字不少時,cell底部距imageview底部超過20,與detailLabel底部高度維持20.佈局


storyboard上的準備工做 

注意將detailLabel numberOfLines 設爲0測試

建好cell自定義AutoCell 類,關聯好控件,事先準備好一些數據源

    nameArray = [NSMutableArray arrayWithObjects:@"蝸殼",@"AI",@"大詹皇",nil];
    imageArray = [NSMutableArray arrayWithObjects:@"u=4040080498,3072784853&fm=90&gp=0.jpg",@"u=2384677404,2895132414&fm=21&gp=0.jpg",@"u=262781505,2408318453&fm=21&gp=0.jpg", nil];
    descriptionArray = [NSMutableArray arrayWithObjects:@"蝸殼打球好瀟灑,好飄逸,鐵王之王",@"AI,史上最矮狀元,無冕之王,crossover簡直厲害,觀賞性強,永遠的MVP!!!!",@"最年輕的一萬分先生,MVP,奧布萊恩杯,效率之王,天之驕子,全宇宙最強的球員沒有之一,強突暴扣身體棒,髮際線又高了,關鍵時刻又聳了,帶領騎士奪冠吧,雖然看起來還沒戲!!!!!!", nil];

實現tableview的委託方法

//numberOfRows
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 3;
}
//cellForRow
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    AutoTableViewCell *cell = (AutoTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"autoCell"];
    [cell.titleLabel setText:nil];
    [cell.titleLabel setText:[nameArray objectAtIndex:indexPath.row]];
    [cell.descriptionLabel setText:nil];
    [cell.logoImageView setImage:[UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]]];
    [cell.descriptionLabel setText:[descriptionArray objectAtIndex:indexPath.row]];
    return cell;
}

先不實現HeightForRow方法,直接運行,發現ios7,ios8上都沒有獲得想要的效果spa

IT'S SO BAD!!!code

核心部分,HeightForRow方法實現

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static AutoTableViewCell *cell = nil;
    static dispatch_once_t onceToken;
    //只會走一次
    dispatch_once(&onceToken, ^{
        cell = (AutoTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"autoCell"];
    });
    
    //calculate
    CGFloat height = [cell calulateHeightWithtTitle:[nameArray objectAtIndex:indexPath.row] desrip:[descriptionArray objectAtIndex:indexPath.row]];
    
    return height;
}

具體的計算高度方法是如今自定義cell類中

-(CGFloat)calulateHeightWithtTitle:(NSString*)title desrip:(NSString*)descrip
{
    //這裏很是重要
    CGFloat preMaxWaith =[UIScreen mainScreen].bounds.size.width-108;
    [self.detailLabel setPreferredMaxLayoutWidth:preMaxWaith];
    [self.titleLabel setText:title];
    //這也很重要
    [self.detailLabel layoutIfNeeded];
    [self.detailLabel setText:descrip];
    [self.contentView layoutIfNeeded];
    CGSize size = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    //加1是關鍵
    return size.height+1.0f;
}

幾大須要注意的地方

  • 首先說爲何要設置 PreferredMaxLayoutWidth, 表示label的最大的佈局寬度,label顯示多少行與它的寬度確定有關,全部這裏要設置正確的寬度,但這裏有點坑的地方orm


這是storyboard 上detailLabel 的該屬性,默認是沒有勾選的(automatic)表示系統自動計算最大布局寬度,可是查看官方文檔,你會發現自動計算只有在ios8中才會有效果,低於ios8不會自動計算。這時你可能會說:那把它勾上吧!!!

如圖,勾上以後你發現顯示的是492,這是什麼意思?這個數字是當前使用的storyboard 的寬度減去label到兩邊界的絕對距離。xcode6 爲大尺寸storyboard 寬度600 ,減去 detailLabel 距左邊界98,減去距右邊界10,恰好492.

可是這樣對嗎?很明顯不對,iphone 屏幕寬度不是已經有3種寬度了麼?320、375(iphone6)、414(plus)

因此600很明顯不對,應該用當前運行的寬度來減去108,因此這裏勾不勾都是錯,乾脆不勾了直接代碼算吧....

CGFloat preMaxWaith =[UIScreen mainScreen].bounds.size.width-108;
  • 關於layoutIfNeeded究竟是幹嗎的,我也是隻知其一;不知其二,只知道不加效果出不來,打算以後再去查閱...

  • 加1是關鍵 

[self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height+1.0f;

這裏size.height 其實是咱們要的contentview 的高度,可是咱們若是直接將這個高度返回,就賦給了cell的高度,可是因爲cell 分界線的緣由,cell的高度比contentview高度多1,因此這裏加1再返回。不要小看1像素,少了它效果還真就出不來!!!!

注意了這些,咱們再運行,發現獲得了想要的效果,切換模擬器,也沒問題。


在ios6.0上測試

沒有6.0的模擬器了,找了臺6.0的真機,測試後效果如圖

 

detailLabel的高度始終沒有改變,維持在一行,可是能夠發現cell的高度是對的,這彷佛說明heightforrow方法沒問題,那detailLabel爲什麼沒有自動拉伸呢?

再次檢查了代碼,原來問題出在cellforrow方法中,由於每一個cell上的detailLabel的高度要拉伸就應該給每一個detailLabel設置最大布局寬度:preferredMaxLayoutWidth。以前作的僅僅只是在heightforrow裏面的獲得那個用來計算的cell設置過。因此加了幾句代碼

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    AutoTableViewCell *cell = (AutoTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"autoCell"];
    [cell.titleLabel setText:nil];
    [cell.titleLabel setText:[nameArray objectAtIndex:indexPath.row]];
    //補上的幾句,給用來顯示的DetailLabel 設置最大布局寬度
    CGFloat preMaxWaith =[UIScreen mainScreen].bounds.size.width-108;
    [cell.detailLabel setPreferredMaxLayoutWidth:preMaxWaith];
    [cell.detailLabel layoutIfNeeded];

    [cell.detailLabel setText:nil];
    [cell.logoImageView setImage:[UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]]];
    [cell.detailLabel setText:[descriptionArray objectAtIndex:indexPath.row]];
    return cell;
}

再次運行,能夠看到在ios6中也獲得了想要的效果,

IT'S perfect!!!

總之,研究了幾天佈局,發現ios好坑,各類陷阱,好在查閱了中外各類資料,最終仍是實現了效果。

項目源碼:https://github.com/zhangxh6931/AutolayoutCell

相關文章
相關標籤/搜索