有了Auto Layout,爲何你仍是懼怕寫UITabelView的自適應佈局?

Apple 算是最重視應用開發體驗的公司了.從Xib到StoryBoard,從Auto Layout到Size Class,每一次的更新,都會給iOS應用的開發帶來不小的便利.可是,對於絕對多數iOS攻城獅來講,咱們依然仍是很懼怕寫UITabelVIew的自適應佈局.固然,懼怕不是由於咱們不會寫,或者自己有什麼特殊的技術點,而是由於太麻煩.固然,文章的後半部分,會給出相應的解決方案,畢竟本文不是爲了吐槽而吐槽.html

UITabelView的自適應佈局有多麻煩?

數據類型的不肯定性:種類越多,頁面越複雜.

網易新聞

以網易新聞的客戶端爲例,可能的數據包括文字新聞,圖片新聞,圖集,推廣,視頻等.每一種數據,又根據來源或點擊量等細分出許多不一樣的狀態.基本上每種數據類型,都至少須要一種單獨的Cell去呈現,每個Cell的佈局,都要單獨去寫.因此說,數據的類型將直接決定頁面自己的複雜度.ios

數據長度的不肯定性: 不肯定字段越多,迭代成本越高.

新浪微博

上圖取自新浪微博.稍微有點經驗的iOS攻城獅,都猜到我要吐槽什麼了吧!沒錯,就是同種數據類型,可是內部字段的長度可能不一樣,並且還要都要給他們顯示出來!其實我也很但願自家的應用都像網易那樣,固定長度顯示新聞,顯示不完,就直接截斷--惋惜那樣的應用都是別人公司的應用.可能你會說: 頂部給個非微博正文區域給個固定高度;文字區域動態計算出高度;圖片部分,圖片高度固定,根據數量動態計算高度;轉發部分同理;而後根據數據在tabelView的代理方法 tableView:heightForRowAtIndexPath: 中動態返回高度便可.是的,思路就是這麼個思路,可是你肯定產品經理一直不會改需求?你肯定不須要適配 6plus時,字號要大點?你肯定本身的應用不但願大屏上同樣能顯示更多的圖片?你肯定老闆不是盤算着 iPad版也交給你維護?因此說,對於這種數據長度不肯定,可是又要求徹底顯示的設計,最複雜的不在於實現,而在於後期的迭代.可變字段越多,迭代越複雜.若是連顯示方式都改了,那就基本等於重作了幾遍.git

cell高度計算有坑: 難以理解的詭異問題

tableView:heightForRowAtIndexPath: 中計算高度時,是有坑的,對於剛接觸iOS的攻城獅來講,幾乎是難以理解的詭異問題.這裏簡單說兩個,其餘的你們可跟帖補充:github

1.文字高度計算時 0.1 高度偏差問題.

cell中常常須要使用 textRectForBounds: limitedToNumberOfLines: 來計算某一個文字的顯示高度.這裏,其實有一個很大的坑的,若是你沒遇到只能說明你很幸運.因爲浮點數四捨五入機制的存在,因此偶現UILabel最後一行沒法顯示的狀況.緣由也很詭異: 在你計算時,部分值會存在稍許的不超過0.01的偏差,大多數狀況下,這個偏差值,能夠安全忽略,可是確實存在那0.01偏差恰好是絕對換行與不換行的分界值,由於0.01的偏差,可能計算出來的高度就不足以顯示最後幾個文字.爲了安全起見,若是須要計算文本高度,我都是加上一個額外的0.1來保證最後一行確定能夠顯示.安全

2.手動調用 tableView:cellForRowAtIndexPath: 獲取cell,引發的卡頓問題.

這個可能也是一些有經驗的開發者也會混淆的問題: 不要在本身的代碼中調用 tableView:cellForRowAtIndexPath: 方法來獲取某一個位置的 cell,來進行關於這個cell的某些計算,由於你手動調用這個方法產生的cell不會參與cell的複用! 各類原因,不過多解釋,總之結論就是,只要系統本身調用 tableView:cellForRowAtIndexPath: 方法產生的 cell纔會參與cell的複用. 關於這個話題,比較易犯的錯誤是,居然有開發者在less

tableView:heightForRowAtIndexPath: 中調用 tableView:cellForRowAtIndexPath: 來獲取cell,而後計算cell高度.而後你會發現,凡是稍微涉及到圖片顯示的界面,你的顯示是對的,可是滾動很是卡頓,由於你在本身渾然不覺的狀況下建立了N個Cell,並且這些Cell絕對不會參與複用.佈局

爲何我如今再也不懼怕寫UITabelView的自適應佈局?

是的,我如今一點也不擔憂去處理各類UITabelView佈局.不是由於我有一股所謂的不畏艱難的偉大工做精神,而是由於我切實找到了解決辦法.具體該怎麼作呢?優化

1.使用AutoLayout 佈局你的cell

坦白說,咱都不是剛入行的人,使用AutoLayout佈局,寫一個自適應的Cell,你們估計也都會.能夠用xib,也能夠用純代碼寫.若是準備用純代碼寫,建議你先好好研究下 Masonry — 使用純代碼進行iOS應用的autolayout自適應佈局設計

2.使用 UITableView-FDTemplateLayoutCell 根據單元格內容的約束自適應單元格高度

博客討論

坦白說,我原來也是: 雖然cell用着AutoLayout,可是計算cell高度時,也是看着設計圖返回一個適合的值--想一想都虐心.前天,一個熱心的開發者在我博客留言說: 他用 Masonry 進行Cell的高度自適應時遇到了問題.我第一反應是: Masonry 能用來計算cell高度?! 而後,他提到了一個第三方UITableView-FDTemplateLayoutCell,好像是國內的大神寫的,具體介紹能夠看這裏: 優化UITableViewCell高度計算的那些事.這篇文章的博主關於 UITableView-FDTemplateLayoutCell 分析很詳盡,用一句總結就是: 一行代碼解決cell高度動態計算問題.代理

3.一個關於Masonry 和 UITableView-FDTemplateLayoutCell結合使用的小例子

 一個關於Masonry 和 UITableView-FDTemplateLayoutCell結合使用的小例子

示例下載地址: 點擊下載

很是感謝 @將來帥哥 的討論,給了我很大啓發和幫助,我也如約作了一個關於Masonry 和 UITableView-FDTemplateLayoutCell結合使用的小例子,以解決他的問題:關於如何讓左側圖片底部老是不被遮蓋.

核心代碼片斷:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    CGFloat height = [tableView fd_heightForCellWithIdentifier: NSStringFromClass([YFAutoLayoutCell class]) cacheByIndexPath:indexPath configuration:^(YFAutoLayoutCell * cell) {
        YFAutoLayoutCellModel * model = [self.data objectAtIndex: indexPath.row];
        
        cell.model = model;
    }];
    
    return height;
}
/**
 *  初始化視圖.
 */
- (void) setupView
{
    self.imgView = [[UIImageView alloc] init];
    self.introLabel = [[UILabel alloc] init];
    
    [self.contentView addSubview: self.imgView];
    [self.contentView addSubview: self.introLabel];
    
    self.introLabel.numberOfLines = 0;
    
    [self.imgView makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.equalTo(8);
        make.size.equalTo(CGSizeMake(60, 60));
        make.bottom.lessThanOrEqualTo(-8); // 這裏是關鍵
    }];
    
    [self.introLabel makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.imgView.right).offset(8);
        make.top.equalTo(self.imgView);
        make.right.equalTo(-8);
        make.bottom.equalTo(-8);
    }];
}

小結

有了Auto Layout,爲何你仍是懼怕寫UITabelView的自適應佈局?由於你還在用傳統的方式去計算cell的高度! Auto Layout + UITableView-FDTemplateLayoutCell + Masonry,耐心研究幾個小時,絕對讓你受益不淺!

相關文章
相關標籤/搜索