iOS-談一談自適應(yīng)Cell的高度緩存

目錄

  • 系統(tǒng)如何計(jì)算的自適應(yīng)高度寻行?
  • 系統(tǒng)計(jì)算的行高會(huì)不會(huì)被緩存?
  • 如何緩存?
  • 勘誤

前幾天讀文檔的時(shí)候發(fā)現(xiàn)一對(duì)方法

- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize NS_AVAILABLE_IOS(6_0); 
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority NS_AVAILABLE_IOS(8_0);

具體可以參閱《iOS文檔補(bǔ)完計(jì)劃--UIView》中的相關(guān)解釋虫腋。

簡(jiǎn)而言之這兩個(gè)方法會(huì):

返回Auto Layout后內(nèi)容高度

并且、我們都知道UITableView、如果設(shè)置成rowHeight = UITableViewAutomaticDimension的話辛掠。cell的高度將由系統(tǒng)通過Auto Layout自動(dòng)計(jì)算憋他。


  • 系統(tǒng)如何計(jì)算的自適應(yīng)高度?

而這個(gè)計(jì)算亲铡、是否通過上面兩個(gè)方法呢才写?

經(jīng)過試驗(yàn)葡兑、答案是肯定的。

系統(tǒng)調(diào)用的正是- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority NS_AVAILABLE_IOS(8_0);這個(gè)方法赞草。


  • 系統(tǒng)計(jì)算的行高會(huì)不會(huì)被緩存?

經(jīng)過試驗(yàn)讹堤、答案是否定的。也就是系統(tǒng)不會(huì)緩存計(jì)算過的行高

這里有兩個(gè)能夠讓Cell自適應(yīng)的方式

  1. 對(duì)UITableView進(jìn)行設(shè)置
tableView.rowHeight = UITableViewAutomaticDimension
  1. 通過代理返回
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

結(jié)果是無(wú)論使用哪個(gè)方法房资、在每次Cell即將被展示的時(shí)候蜕劝、都會(huì)自動(dòng)調(diào)用上述的systemLayoutSizeFittingSize方法。

兩個(gè)關(guān)鍵的步驟是:
  1. 通過cellForRowAtIndexPath對(duì)某個(gè)Cell進(jìn)行配置
    而我們?cè)谶@一步已經(jīng)將Cell的內(nèi)容配置完畢了
  2. 通過[UITableView _heightForCell:atIndexPath:]計(jì)算Cell高度
    而內(nèi)部則調(diào)用systemLayoutSizeFittingSize獲取具體的高度轰异。

  • 如何緩存?

經(jīng)過以上兩個(gè)探索岖沛、我們已經(jīng)知道Cell通過systemLayoutSizeFittingSize高度、并且不會(huì)被緩存搭独。

那么婴削、我們需要做的就是自己計(jì)算高度、并且緩存牙肝。直接貼一下代碼:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    BSQuestionsModel * model = _dataArray[indexPath.section];
    return model.cell_height?:UITableViewAutomaticDimension;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    BSQuestionsModel * model = _dataArray[indexPath.section];
    BSQuestionsTableViewCell * cell = [BSQuestionsTableViewCell cellForTableView:tableView model:model];
    
    //高度緩存
    CGFloat height = [cell systemLayoutSizeFittingSize:CGSizeMake(tableView.frame.size.width, 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel].height;
    model.cell_height = height;
    
    return cell;
}

這樣唉俗、cell在進(jìn)行過一次高度計(jì)算之后。就不需要在計(jì)算第二次了

然后關(guān)于上面的代碼有幾點(diǎn)需要說(shuō):
  1. 為什么在cellForRowAtIndexPath里做緩存
    最開始我們已經(jīng)談過了配椭、cellForRowAtIndexPath的調(diào)用在獲取自動(dòng)布局的高度之前虫溜、這樣也能避免重復(fù)取用對(duì)應(yīng)位置的Cell。前提是你開啟了預(yù)估行高股缸、具體見下面的解釋衡楞。
這里需要補(bǔ)充一下cellForRowAtIndexPathheightForRowAtIndexPath調(diào)用到底誰(shuí)先誰(shuí)后:
  1. 如果你的tableView設(shè)置了預(yù)估行高
    cellForRowAtIndexPath永遠(yuǎn)在heightForRowAtIndexPath之前
  2. 如果你的tableView沒有設(shè)置預(yù)估行高
    tableView首先會(huì)把所有IndexPath的heightForRowAtIndexPath輪訓(xùn)一遍以計(jì)算contentSize。而后按照情況1的順序敦姻。

具體可以參閱《iOS-談?wù)刄ITableView中estimatedRowHeight到底該不該禁用》

所以如果你想不設(shè)置預(yù)估行高瘾境、又想用這種方式緩存的話。需要把緩存的代碼寫在heightForRowAtIndexPath而不是cellForRowAtIndexPath

而返回的UITableViewAutomaticDimension主要是為了容錯(cuò)(比如上面的情況)镰惦。

  1. 為什么用systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority
    網(wǎng)上很多帖子都這樣寫:
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]

但是在我這不太好用迷守、因?yàn)槲襝ell內(nèi)部有一些優(yōu)先級(jí)的設(shè)置。

所以旺入、我干脆和系統(tǒng)調(diào)用的方式一樣兑凿。

  1. 異步計(jì)算
    是的、我們又可以異步計(jì)算了茵瘾。雖然我沒寫急膀、因?yàn)槲椰F(xiàn)在得抓緊碼頁(yè)面~
關(guān)于一些舊帖子

我搜到的都是14/15年的帖子、和現(xiàn)在的情況感覺還是有出入的龄捡。

  1. cell.contentView取出的高度要+1
    網(wǎng)上對(duì)+1的解釋是卓嫂、cellcell.contentView要搞出1個(gè)單位。還附上了兩張圖聘殖。

但是現(xiàn)在晨雳、cell是比cell.contentView高出0.5(0.5也不一定準(zhǔn)確行瑞、xib上有四舍五入的嫌疑)、而不是1餐禁。

  1. cell還是用cell.contentView
    我在網(wǎng)上搜了很多帖子血久、都說(shuō)要使用cell.contentView
    但是我用cell一樣可以獲取高度。所以用cell唄~

勘誤

不好意思今天是2019.11.29帮非,時(shí)隔一年半了才發(fā)現(xiàn)這個(gè)事氧吐。因?yàn)榭戳?a href="http://www.reibang.com/p/38b43dff4e93" target="_blank">Bruce_XHG大佬的文章
不過其實(shí)也不算是勘誤、只是發(fā)現(xiàn)個(gè)更好的方法

由于我以前很少使用willDisplayCell這個(gè)方法(其實(shí)現(xiàn)在也是)末盔,所以一直沒發(fā)現(xiàn):
實(shí)際上對(duì)于自適應(yīng)的cell筑舅,只要你在cellForRowAtIndexPath里配置好了,willDisplayCell中返回的cell其實(shí)已經(jīng)被系統(tǒng)計(jì)算過了陨舱。
我們可以省去自己計(jì)算的部分翠拣,也不需要擔(dān)心自己算的不對(duì)。上面的反面教材就不刪了

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    GKTMessageItemModel *model = self.dataArr[indexPath.row];
    UITableViewCell<GKTMessageListTableViewCellProtocol> *cell = [self factoryCellWithTableView:tableView model:model row:indexPath.row];
    
    //這個(gè)頁(yè)面對(duì)cell與model進(jìn)行了進(jìn)一步的解耦游盲,改的時(shí)候如果對(duì)邏輯不清晰误墓,可以參閱。
    //http://www.reibang.com/p/723e8435586d#comment-38321201
    [cell configCellWithModel:model indexPath:indexPath];

    return cell;
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    GKTMessageItemModel *model = self.dataArr[indexPath.row];
    //高度緩存
    if (model.cell_height == 0) {
        CGFloat height = cell.height;
        model.cell_height = height;
    }
}

最后

本文主要是自己的學(xué)習(xí)與總結(jié)益缎。如果文內(nèi)存在紕漏谜慌、萬(wàn)望留言斧正。如果愿意補(bǔ)充以及不吝賜教小弟會(huì)更加感激莺奔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末欣范,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弊仪,更是在濱河造成了極大的恐慌,老刑警劉巖杖刷,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件励饵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡滑燃,警方通過查閱死者的電腦和手機(jī)役听,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)表窘,“玉大人典予,你說(shuō)我怎么就攤上這事±盅希” “怎么了瘤袖?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)昂验。 經(jīng)常有香客問我捂敌,道長(zhǎng)艾扮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任占婉,我火速辦了婚禮泡嘴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逆济。我一直安慰自己酌予,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布奖慌。 她就那樣靜靜地躺著抛虫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪升薯。 梳的紋絲不亂的頭發(fā)上莱褒,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音涎劈,去河邊找鬼广凸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蛛枚,可吹牛的內(nèi)容都是我干的谅海。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蹦浦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扭吁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盲镶,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤侥袜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后溉贿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枫吧,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年宇色,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了九杂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宣蠕,死狀恐怖例隆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抢蚀,我是刑警寧澤镀层,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站皿曲,受9級(jí)特大地震影響鹿响,放射性物質(zhì)發(fā)生泄漏羡微。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一惶我、第九天 我趴在偏房一處隱蔽的房頂上張望妈倔。 院中可真熱鬧,春花似錦绸贡、人聲如沸盯蝴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捧挺。三九已至,卻和暖如春尿瞭,著一層夾襖步出監(jiān)牢的瞬間闽烙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工声搁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黑竞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓疏旨,卻偏偏與公主長(zhǎng)得像很魂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子檐涝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353