tableView的cell采用cell自適應(yīng)高度,并且各個(gè)cell高度不同的情況下,在reload時(shí),tableView可能會(huì)發(fā)生異常抖動(dòng)。
原因就是因?yàn)闆]有實(shí)現(xiàn)返回高度的代理,tableView刷新渲染時(shí),并不明確cell的高度具體會(huì)是多少,以及cell自適應(yīng)高度的機(jī)制問題??赡艿漠惓0l(fā)生邏輯就是系統(tǒng)先拿模糊高度進(jìn)行渲染,當(dāng)cell高度確定后,又調(diào)整了高度,所以發(fā)生的抖動(dòng)。
我的解決方式如下:
willDisplayCell時(shí)用字典緩存cell的高度-> estimatedHeightForRowAtIndexPath方法返回
用字典存儲(chǔ)cell出現(xiàn)后的高度,刷新時(shí)讓系統(tǒng)使用我們對(duì)于每個(gè)cell緩存的高度。
#pragma mark - 解決動(dòng)態(tài)cell高度 reloadData刷新抖動(dòng)的問題
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
_estimatedRowHeightCache[indexPath] = @(cell.frame.size.height);
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [_estimatedRowHeightCache[indexPath] floatValue] ?:50; // 為0時(shí)最好返回最接近的預(yù)估高度
}
tip:
1. 一般情況下不是動(dòng)態(tài)變化的界面字典的key值可以用indexPath,而如果cell位置會(huì)動(dòng)態(tài)變化,或者隱藏顯示后刷新界面,key值就不能使用indexPath, 高度緩存對(duì)應(yīng)關(guān)系會(huì)是錯(cuò)的, 應(yīng)該使用cell對(duì)應(yīng)的界面類型/業(yè)務(wù)類型,否則依然會(huì)有抖動(dòng)問題。
對(duì)于每個(gè)cell對(duì)應(yīng)一個(gè)model的情況,我們可以將高度緩存至model中
#pragma mark - 解決動(dòng)態(tài)cell高度 reloadData刷新抖動(dòng)的問題
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
DemoModel *model = self.dataArray[indexPath.row];
model.esHegiht = cell.frame.size.height;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
DemoModel *model = self.dataArray[indexPath.row];
return model.esHegiht?:50; // 為0時(shí)最好返回最接近的預(yù)估高度
}
對(duì)于所有cell對(duì)應(yīng)一個(gè)model的情況,比如一些詳情頁(yè),我們可以以cell的類型緩存高度
/**
偽代碼
*/
- (void)buildDataArray {
// tableView數(shù)據(jù)源推薦使用這種方式 可以擺脫if indexPath.row的判斷,方便維護(hù)。
// 可以不使用枚舉,使用字符串,cell的類名都可以,根據(jù)業(yè)務(wù)。
self.dataArray = @[@(InfoCellType1),@(InfoCellType2)];
}
#pragma mark - 解決動(dòng)態(tài)cell高度 reloadData刷新抖動(dòng)的問題
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
InfoCellType type = [self.dataArray[indexPath.row] integerValue];
__weak typeof(self) weakSelf = self;
DemoTableViewCell *cell;
switch (type) {
case InfoCellType1:
cell = [tableView dequeueReusableCellWithIdentifier:@"cellId1" forIndexPath:indexPath];
break;
case InfoCellType2:{
cell = [tableView dequeueReusableCellWithIdentifier:@"cellId2" forIndexPath:indexPath];
}
break;
default:
break;
}
cell.model = self.infoModel;
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
// 取出對(duì)應(yīng)的界面類型
NSNumber *typeNumber = self.dataArray[indexPath.row];
_estimatedRowHeightCache[typeNumber] = @(cell.frame.size.height);
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *typeNumber = self.dataArray[indexPath.row];
return [_estimatedRowHeightCache[typeNumber] floatValue] ?:50; // 為0時(shí)最好返回最接近的預(yù)估高度
}