咱們常常會遇到UITableViewCell的高度要跟隨內容而調整,在未引入AutoLayout以前,咱們使用如下方法計算Label高度,而後heightForRowAtIndexPath中返回計算的高度,這種作法,真的很土很侷限很很差,若是UILabel使用了CoreText或者UIKit進行了富文本不一樣字體的排版,它更是沒辦法,我還得分段來計算,總之各類麻煩。安全
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode NS_DEPRECATED_IOS(2_0, 7_0, "Use -boundingRectWithSize:options:attributes:context:"); // NSTextAlignment is not needed to determine size
本系列文章咱們討論的是AutoLayout,那iOS6引入AutoLayout以後,狀況是否有所變化呢?固然!並且AutoLayout在iOS不斷更新過程當中,也在一塊兒不斷的優化,以方便開發者進行佈局。說實話,跟不少開發者同樣,我目前也並非特別喜歡AutoLayout,有一些不可控的因素,佈局並無徹底掌握在本身手上,須要依賴系統根據約束進行調整,這讓保守的開發人員很沒有安全感。不廢話了,咱們仍是進入到正題。佈局
咱們直接拿一個現實的需求來進行討論,以下圖,咱們須要構建一個頁面,上面部分顯示咱們預定保養的基本信息,下面部分顯示該門店目前提供的優惠券列表,這種需求最簡單的作法就是直接用兩種UITableViewCell,下面的部分的UITableViewCell要簡單一些,高度固定,而上面部分的UITableViewCell的內容有不少不肯定的內容,好比用戶預定保養選擇的項目,門店的名稱地址,這些UILabel的高度都不肯定,因此致使上面部分的UITableViewCell的高度須要動態調整,這是一個比較典型的實例,咱們一塊兒來看一下如何解決。字體
1、創建合理的約束優化
咱們先創建自定義Cell: AppointmentedInfoCell (建立XIB)。 而後設置合理的約束條件,什麼是合理的約束條件,一方面咱們須要按前面講到的設置正確的約束條件,另外一方面個人意思主要是控件的compression resistance 和 hugging constraints ,在IB中以下圖:spa
咱們知道在Autolayout中,咱們的UILabel,UIButton等控件都有了內建大小(intrinsic content size),就是說控件的大小會根據內容進行自動調整,能夠將這些控件的大小和ScrollView的bounds和contentSize進行對比,意思有點相似,只不過UILabel,UIButton這些控件並不像Scrollview同樣能夠在bounds不等於contentSize的狀況下進行滾動查看內容。 在這裏爲了使用UILabel的內建大小,咱們要保持compression resistance 和 hugging constraints 的垂直方向優先級沒有被更高的優先級所覆蓋,好比更改了UILabel內建大小的優先級(priority),並設置了UILabel的高度約束的優先級高於內建大小的優先級,那內建大小天然就不起做用了,就會以高優先級爲準.code
一方面咱們確保了AppointmentedInfoCell中的控件,目前全是UILabel,其內建大小垂直方向優先級爲最高的1000。 光這個還不夠,咱們還要確保內建大小的邊緣跟隨內建大小一塊兒變化,從而保證咱們的內建大小能夠起做用,說白了,就是要求contentView中的子控件創建與superView的約束,咱們先創建第一個UILabel(姓名、電話)與superview top 的間距約束,而後依次往下創建控件之間推薦間距的約束,左邊同列控件創建左部對齊約束,右邊同行內容的創建頂部對齊約束,垂直方向的間距約束,最底部的」預定結果Label」創建與superview bottom的間距約束。blog
特別提醒:與contentView的四邊間距約束很重要,有了4個與contentView的邊緣約束,才能保證contentView的大小跟隨其subviews變化。內存
上面這些就是創建合理的約束條件,這裏隨便提醒一下,UILabel在IB中佈局的大小若是跟內容計算出來的不一致就會有警告,好比UILabel長度爲200,目前的內容爲2個14號字的長度,那UILabel就會有警告,對於這種警告,你須要忍住你的強迫症。開發
2、計算行高it
這一步在iOS7與iOS8上面就有所不一樣了,咱們先來看最新的iOS8。
一、iOS8:
從iOS8開始引入了UITableViewCell的高度的自適應功能,在iOS8以前實現很麻煩的功能,iOS8之後就不須要本身動手去作了,稍後咱們會看一下iOS7下面如何作。
//打開tableview的高度估算功能 _iTableView.rowHeight = UITableViewAutomaticDimension; _iTableView.estimatedRowHeight = 70.0;
estimatedRowHeight必須設置爲大於0,爲了畫面的過分順暢,保證UITableview的高度變化不至於致使UITableview的大範圍滾動而影響了用戶視覺體驗,咱們用一個預估的平均值,這也就是所謂的預估值。estimatedRowHeight並非最終的行高,當一個Cell須要顯示的時候,會精確計算實際的行高,contentView的寬度就是UITableview的寬度減去Section Index,accessoryView等的寬度,contentView的高度則會自動根據其子視圖的約束關係計算,當此精確值被計算出事後,estimatedRowHeight、tableview的contentSize,bounds,這些都會跟隨更新。
estimatedRowHeight每一行都會使用此值用於該行的預估值,進而初步預估UITableView的contentSize。若是UITableView每行內容變化很大,行高差異很大,那咱們可使用如下方法爲每一行設置各不相同的預估值。也就是說有通用值,也有個性值。
- (void)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
OK,預估值只是一個插曲,咱們來看精確值,在iOS8事後,咱們只需簡單的激活預估值,並在heightForRowAtIndexPath中返回UITableViewAutomaticDimension便可。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (IS_IOS8_OR_ABOVE) { return UITableViewAutomaticDimension; } }
二、iOS7:
UITableViewCell的contentView的高度自適應是iOS8中加入的,iOS7就只能本身計算了,因此咱們來看一下iOS7下如何處理的。
//NIB註冊,獲取自定義UITableView實例的方式有不少種,這裏隨便用一種 UINib *cellNib = [UINib nibWithNibName:@"AppointmentedInfoCell" bundle:nil]; [self.tableView registerNib:cellNib forCellReuseIdentifier:@"AppointmentedInfoCell"]; //先建立一個基本的Cell實例,咱們後面cellForRowAtIndexPath 和 heightForRowAtIndexPath 都須要用,因爲UITableView的加載過程是先計算出全部的行高,再對每行進行渲染的,即 heightForRowAtIndexPath是先調用的,因此這裏的baseCell就是一個離屏控件,用於輔助計算高度的,然後面也能夠直接使用其用於每行內容的更新,每種類型的Cell只須要一個便可,這樣咱們的離屏內存並不會浪費。 _baseCell = [cellNib instantiateWithOwner:nil options:nil][0]; //更新Cell內容 - (void)configureCell:(AppointmentedInfoCell *)cell atIndexPath:(NSIndexPath *)indexPath { //更新contentView的子控件 } // - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { AppointmentedInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppointmentedInfoCell" forIndexPath:indexPath]; [self configureCell:cell atIndexPath:indexPath]; return cell; } // - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { [self configureCell:_baseCell atIndexPath:indexPath]; [_baseCell layoutSubviews]; CGFloat height = [_baseCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; return height + 1;//因爲分割線,因此contentView的高度要小於row 一個像素。 }
OK,到這裏,咱們基本上就掌握了AutoLayout的UITableViewCell的動態高度的處理,關鍵點就是systemLayoutSizeFittingSize的使用,但願本篇可以幫助你更好的理解AutoLayout以及UITableView在iOS8新增的佈局處理。