estimatedRowHeight
(屬性或代理方法),會去獲取全部數據源的cell高度(包括屏幕外,這可能涉及沒必要要的計算)estimatedRowHeight
後,只獲取部分cell高度。- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndex:indexPath]; //會引起死循環,見第一張圖
}
複製代碼
initWithStyle: reuseIdentifier:
designated初始化方法若是cell高度和webview有關,須要在加載完更新高度的話web
如:新聞詳情頁下的推薦文件。 最簡單的作法,在Header中放webView,tableView會本身處理Header的高度
。 webView加載完成後,修改webView的frame,而後刷新tableview的高度。objective-c
另外一種作法較繁瑣,體驗也很差。 思路值得借鑑,經過設置ContentInset,讓WebView做爲subView來處理。緩存
//webview
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// 一開始是webview在滾動,tablview並無滾動。
// 直到webivew到底,其scrollview滑不動了。
// 此時,tableview的scrollview才接管滑動(tableview在webview下面,因此後接收手勢)
// 此時若是下滑,由於禁止了webview的scrollview滑動,因此滑動的是tablview的scrollview。
if(self.tableView.contentOffset.y==0) {
[self.webView.scrollView setScrollEnabled:YES];
}else {
[self.webView.scrollView setScrollEnabled:NO];
}
}
//tableview
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if(self.tableView.contentOffset.y==0) {
[self.webView.scrollView setScrollEnabled:YES];
}else {
[self.webView.scrollView setScrollEnabled:NO];
}
}
複製代碼
單例鍵盤對象
,2相似於MVVM,cell持有本身的數據源、tableview
。UITableViewStyle
。
//delegate for headerInSection
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
//返回的view的frame,決定不了真實高度。
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
//高度由這決定
}
//style是readonly屬性,建立時決定。
//若是是tableviewcontroller,則須要使用xib文件修改。
複製代碼
場景:複雜Cell,層級較深,須要利用VC的資源時。 Cell的內部響應託管給VC。如:頭條刪除新聞要求選緣由的彈框。bash
cell的方法
。如:微博評論展開、微信增長評論等微信
修改tableview的bounds。app
微信聊天窗口,點文本框,對話欄不論contentOffset都滾動到底部 主要是contentSize和bounds。oop
- (void)tableViewScrollsToBottom {
if(self.chatDataArray.count<1){
return;
}
//若是不到一屏,就不拖到最下
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:self.chatDataArray.count-1 inSection:0]];
CGFloat lastCellMaxY = CGRectGetMaxY(cell.frame);
if(cell!=nil && lastCellMaxY<self.tableView.frame.size.height) {
return;
}
CGFloat yOffset = 0;
//若是tableview的contentSize超過table的bounds高度,就向上滾動
if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {
yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
}
[self.tableView setContentOffset:CGPointMake(0, yOffset) animated:NO];
// SHWCRLog([NSString stringWithFormat:@"after tableView.contentSize %f, contentOffset %f", self.tableView.contentSize.height, self.tableView.contentOffset.y]);
}
複製代碼
//TableView
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
AModel *model = self.datas[indexPath.row];
[cell start_show:model.uiModel];
}
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
[cell stop_show];
}
//Cell
- (void)start_show:(AModel*)model {
NSTimer *timer = [NSTimer timerWithTimeInterval:3
target:self
selector:@selector(firedTimer:)
userInfo:model repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//避免cell複用的問題,使用隊列來管理timer。
@synchronized(self.timerArray) {
[self.timerArray addObject:timer];
}
}
- (void)stop_show {
@synchronized(self.timerArray) {
if(self.timerArray.firstObject) {
NSTimer *timer = self.timerArray.firstObject;
[timer invalidate];
[self.timerArray removeObjectAtIndex:0];
}
}
}
- (void)firedTimer:(NSTimer *)timer {
@synchronized(self.timerArray) {
[self.timerArray removeObject:timer];
}
... //埋點
}
複製代碼
網上查了下,說是由於iOS11中對自動高度的默認值改變形成的。能夠經過關閉高度自動設置修復。 iOS10以後,能夠用自帶的refreshControl,iOS開發之UIRefreshControl使用踩坑佈局
Tableview是一個ScrollView,須要知道contentSize,纔能有合理ScrollView的預估。 那麼,Tableview是如何估計contentSize的呢?性能
tableView.rowHeight = 88;
tableView.rowHeight = UITableViewAutomaticDimension;
複製代碼
此時,contentSize= cell高度*數據源個數 + header高度等ui
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// return xxx
}
複製代碼
在沒有設置estimatedRowHeight時,就會詢問每一個cell的高度。
在cell的layoutSubviews
佈局完成後,拿到cell的高度(Masonry的話,要加一句[self layoutIfNeeded]
)。
_tableView.bounces = NO;
_tableView.estimatedRowHeight = 152;
_tableView.rowHeight = UITableViewAutomaticDimension;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
複製代碼
[self.tableView beginUpdates];
[self.tableView endUpdates];
複製代碼
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
複製代碼
全局刷新: [self.tableView reloadData];
修改局部刷新, reloadRowsAtIndexPaths
刪除局部刷新,deleteRowsAtIndexPaths
- (NSArray*)visibleCells;
- (NSArray*)indexPathsForVisibleRows;
複製代碼
//複雜Cell,根據需求看是否持有VC、TableView、VM
@protocol SomeCellDelegate
- (void)onDelClicked:(id)sender; //cell的內部響應託管給VC。如:頭條刪除新聞要求選緣由的彈框。
@end
@property (nonatomic, strong)SomeModel *model;
@property (nonatomic, weak)UIViewController<SomeCellDelegate> * cellDelegate;
@property (nonatomic, weak)UITableView * tableView; //如:cell高度變化,要求TableView刷新高度
//TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
[self setUp];
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self) {
[self setUp];
}
return self;
}
- (void)setUp {
self.backgroundColor = [UIColor colorWithHexString:[SHWRUMetaHolder inst].feed.bgColor alpha:1];
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.contentImageView];
[self.contentView addSubview:self.separateLine];
}
- (void)setModel:(SHWRUNewsWrappedModel *)model {
_model = model;
[self updateContent];
[self updateLayout];
}
- (void)updateLayout {
}
- (void)updateContent {
}
複製代碼