1. 程式人生 > >iOS cell高度自適應 - 教你寫出優雅的table view

iOS cell高度自適應 - 教你寫出優雅的table view

作為一個iOS開發者,自然少不了了table view打交道,table view中最令人頭疼的是各種cell的高度計算了,雖然技術上並不難,但是對於自定義cell來說一旦控制元件比較多,計算起來就會很麻煩,會出現很多和height相關的程式碼,萬一稍有偏差,就要小心老闆和測試大蝦們鄙視的小眼神了。
今晚呢,現在已經是凌晨了~
下面就為大家介紹一種方法,讓你的cell徹底丟棄HEIGHT這玩意兒~

在正式介紹之前,你需要了解約束,如果你熟練運用autolayout或者Masonry這等玩意兒寫約束,那麼你就可以輕鬆理解下面的講述了。如果你意識到這兩個東東不認識你,那麼愛學習的你要利用好網路,去搜索一下Masonry或autolayout,很多大蝦講過著玩倆玩意兒,也很好學,個人推薦Masonry。

下面開始乾貨

首先介紹UITableViewDelegate中的一個方法

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);

這貨是iOS 7之後出現的,作用是返回一個估算的cell高度,如果你的應用支援iOS 7以及之後的版本,那就你就可以高枕無憂的愉快使用了。
按照正常的步驟來說,table view會先走heightForRow方法去獲取高度,然後走cellForRow

方法去初始化和賦值等。但是一旦你的程式碼中出現了這貨,他倆的執行順序就顛倒了,先執行estimatedHeightForRow,其次執行cellForRow,再執行heightForRow,可以見得heightForRow的作用被弱化了。
通過下面的講解,你就會知道heightForRow豈止是被弱化了,這東西幾乎要被拋棄了。

下面以一個最簡單的例子講解怎樣去除惱人的高度計算(講解、程式碼和demo基於Masonry)
分析一下,這個cell中包含兩個label和一個view,一個是顯示在上面的title label(“row : 2 …”),一個是顯示在下面的detail label(“生活如此美好 …”),一個是最底下的灰線。

  1. cell中各個控制元件,先找出有上下關係的,如此cell中title label、detail label和灰線。
  2. 將有上下關係的控制元件的top和bottom約束好,例如這個cell中,title label在detail label上面距離其頂部x,detail label 在灰線上面,距離灰線頂部y。
  3. 最為關鍵的點:給最上面的title的top和最下面的灰線的bottom新增相對於父檢視的約束
  4. 最後愉快的刪除heightForRow並寫上estimatedHeightForRowAtIndexPath方法,return一個你喜歡的數字(當然越接近真實值越好)
    • //label的高度就不需要操心了,因為它會根據內容的多少自適應,這也是之前計算label高度的關鍵
這裡給出上面cell中三個控制元件的約束程式碼
 /**
        請仔細看兩個控制元件之間以及它們和父檢視的約束,主要是top和bottom之間的約束
        1、titleLab在上面,距離父檢視上方和左邊各10畫素
        2、detailLab在titleLab下面,距離titleLab 8畫素,左邊和titleLab對齊,切底部距離bottomLine 10畫素
        3、bottomLine在最下面,左右和底都和父檢視對齊,高度為1
     Label是個好玩的東西,如果有文字,則label有高度,如果內容為空,則高度為0,我們就是利用了它們的這個特性來省區計算高度的步驟
     * 當然,為了使其能自適應高度,我們一般會把label的寬度約束死
     * 程式碼中重點約束已標註 “//重點”
     */

    [self.titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.equalTo(self).offset(10);//重點
        make.right.equalTo(self).offset(-15);
    }];
    [self.detaiLab mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.titleLab);
        make.top.equalTo(self.titleLab.mas_bottom).offset(8);//重點
    }];
    [self.bottomLine mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.detaiLab.mas_bottom).offset(10);//重點
        make.bottom.left.right.equalTo(self); //重點
        make.height.mas_equalTo(1);
    }];

通過上面三個步驟,cell以及其中的三個控制元件的上下約束已經完成。現在給title label和detail label填充內容,它們的高度隨文字自適應,那麼cell的高度也會隨著label的高度的改變而改變(因為它們之間的上下關係已經約束好了嘛)
這個時候estimatedHeightForRowAtIndexPath這貨就該出場了,為什麼呢?因為有了它和約束就不需要再去手動指定高度了啊(給cell中控制元件賦值完成的時候也就是其高度確定了的時候,如果heightForRow方法走之前能夠確定這個cell的高度,那它的存在也就沒有任何意義了,當然這裡一定要在cellForRow這個方法中對控制元件賦值,這對於習慣在willDisplayCell中賦值的童鞋來說是個悲劇,不信你可以試試)~後知後覺了嘛?

運用這個方法省區高度計算最為核心的核心是:cell的top和bottom和其中控制元件之間的約束正確無誤,否則會出現什麼意想不到的問題我就不知道了~

內容就上面這些了,不知道我有沒有講清楚,也不知道你有沒有心領神會和恍然大悟。有不理解的地方和講得不對的地方,歡迎下方留言討論。

時間已近凌晨兩點,想想今天(週六)還要加班,趕緊去睡了,淚流滿面的時間都沒有~