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