- 系統(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)的方式
- 對(duì)UITableView進(jìn)行設(shè)置
tableView.rowHeight = UITableViewAutomaticDimension
- 通過代理返回
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
結(jié)果是無(wú)論使用哪個(gè)方法房资、在每次Cell即將被展示的時(shí)候蜕劝、都會(huì)自動(dòng)調(diào)用上述的systemLayoutSizeFittingSize
方法。
兩個(gè)關(guān)鍵的步驟是:
- 通過
cellForRowAtIndexPath
對(duì)某個(gè)Cell進(jìn)行配置
而我們?cè)谶@一步已經(jīng)將Cell的內(nèi)容配置完畢了 - 通過
[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ō):
- 為什么在
cellForRowAtIndexPath
里做緩存
最開始我們已經(jīng)談過了配椭、cellForRowAtIndexPath
的調(diào)用在獲取自動(dòng)布局的高度之前虫溜、這樣也能避免重復(fù)取用對(duì)應(yīng)位置的Cell。前提是你開啟了預(yù)估行高股缸、具體見下面的解釋衡楞。
這里需要補(bǔ)充一下
cellForRowAtIndexPath
與heightForRowAtIndexPath
調(diào)用到底誰(shuí)先誰(shuí)后:
- 如果你的tableView設(shè)置了預(yù)估行高
cellForRowAtIndexPath
永遠(yuǎn)在heightForRowAtIndexPath
之前- 如果你的tableView沒有設(shè)置預(yù)估行高
tableView首先會(huì)把所有IndexPath的heightForRowAtIndexPath
輪訓(xùn)一遍以計(jì)算contentSize
。而后按照情況1的順序敦姻。
所以如果你想不設(shè)置預(yù)估行高瘾境、又想用這種方式緩存的話。需要把緩存的代碼寫在heightForRowAtIndexPath
而不是cellForRowAtIndexPath
里
而返回的UITableViewAutomaticDimension
主要是為了容錯(cuò)(比如上面的情況)镰惦。
- 為什么用
systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority
網(wǎng)上很多帖子都這樣寫:
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]
但是在我這不太好用迷守、因?yàn)槲襝ell內(nèi)部有一些優(yōu)先級(jí)的設(shè)置。
所以旺入、我干脆和系統(tǒng)調(diào)用的方式一樣兑凿。
- 異步計(jì)算
是的、我們又可以異步計(jì)算了茵瘾。雖然我沒寫急膀、因?yàn)槲椰F(xiàn)在得抓緊碼頁(yè)面~
關(guān)于一些舊帖子
我搜到的都是14/15年的帖子、和現(xiàn)在的情況感覺還是有出入的龄捡。
-
cell.contentView
取出的高度要+1
網(wǎng)上對(duì)+1的解釋是卓嫂、cell
比cell.contentView
要搞出1個(gè)單位。還附上了兩張圖聘殖。
但是現(xiàn)在晨雳、cell是比cell.contentView高出0.5(0.5也不一定準(zhǔn)確行瑞、xib上有四舍五入的嫌疑)、而不是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ì)更加感激莺奔。