UITableView的那些事儿

    本文的背景是,在实际项目中,咱们常常会遇到TabelView的cell高度须要根据内容自适应,但cell的高度不是应该在cell显示前就已经设置好了吗?如何才能根据内容自适应高度?为此咱们一探TabelView运行的机制.git

    下面给出本例的日志
github

2016-01-28 10:15:18.981 SimpleImChat[1370:40265] viewDidLoad
2016-01-28 10:15:18.982 SimpleImChat[1370:40265] viewWillAppear
2016-01-28 10:15:18.993 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:15:18.994 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:15:18.997 SimpleImChat[1370:40265] viewWillLayoutSubviews
2016-01-28 10:15:18.999 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:15:18.999 SimpleImChat[1370:40265] viewDidLayoutSubviews
2016-01-28 10:15:19.000 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:15:19.001 SimpleImChat[1370:40265] -[ChatViewController tableView:cellForRowAtIndexPath:]:0
2016-01-28 10:15:19.056 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:15:19.058 SimpleImChat[1370:40265] viewWillLayoutSubviews
2016-01-28 10:15:19.059 SimpleImChat[1370:40265] viewDidLayoutSubviews
2016-01-28 10:15:19.064 SimpleImChat[1370:40265] viewDidAppear

能够看到heightForRowAtIndexPath执行屡次,并且是先于cellForRowAtIndexPath执行的,那么咱们是否是应该在heightForRowAtIndexPath里面提早设置好cell的高度,而后cellForRowAtIndexPath执行的时候就已经能够正确的显示了呢?那么如何才能正确获取到cell的高度呢,cellForRowAtIndexPath执行前应该尚未数据的,有人会想到在heightForRowAtIndexPath里面先给cell设数据,而后算好高度再取出来,对于IOS6及如下的版本,这倒是一种解决方案.但对于IOS7及以上的版本,这样作将大大下降执行效率,由于heightForRowAtIndexPath会执行屡次,每次都去计算高度将很耗时.So,IOS7有了这样的代理和属性缓存

// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.
// If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);

@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is 0, which means there is no estimate

这里是IOS的UITableView.h文件中的声明,这里要注意里面的注释,根据注释,咱们知道,若是设置了estimatedRowHeight或者实现了estimatedHeightForRowAtIndexPath代理,就不会频繁调用heightForRowAtIndexPath了,然并卵,看LOGui

2016-01-28 10:26:30.175 SimpleImChat[1462:49281] viewDidLoad
2016-01-28 10:26:30.176 SimpleImChat[1462:49281] viewWillAppear
2016-01-28 10:26:30.189 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0
2016-01-28 10:26:30.190 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0
2016-01-28 10:26:30.194 SimpleImChat[1462:49281] viewWillLayoutSubviews
2016-01-28 10:26:30.195 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0
2016-01-28 10:26:30.196 SimpleImChat[1462:49281] viewDidLayoutSubviews
2016-01-28 10:26:30.198 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0
2016-01-28 10:26:30.198 SimpleImChat[1462:49281] -[ChatViewController tableView:cellForRowAtIndexPath:]:0
2016-01-28 10:26:30.254 SimpleImChat[1462:49281] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:26:30.257 SimpleImChat[1462:49281] viewWillLayoutSubviews
2016-01-28 10:26:30.257 SimpleImChat[1462:49281] viewDidLayoutSubviews
2016-01-28 10:26:30.261 SimpleImChat[1462:49281] viewDidAppear

这里咱们能够清楚的看到,当实现了estimatedHeightForRowAtIndexPath代理后,是先执行cellForRowAtIndexPath后执行atom

heightForRowAtIndexPath,so,你能够在cellForRowAtIndexPath中算好高度而后存下来,存到哪里?存到View?存到model?其实均可以,但cell有重用,为防止取错cell(如何才是正确的取法?读者能够思考一下),咱们将算好的高度存在model里,这里你能够给model加一个属性,或者动态绑定一个属性,这样在ViewController中,咱们是可以拿到全部数据的,而后根据indexPath是能够正确取到当前cell对应的model的,这里的model已经在cellForRowAtIndexPath执行的时候经过给view赋值算好了高度,而且存了下来.说了这么多,可能有点凌乱了.spa

这里附上代码 git代码
代理

须要说明一下若是在viewDidLoad中设置了estimatedRowHeight就不用实现对应的代理了,并且通常状况这个预估高度都是定值,可是不能随便设置,不能随便设置,不能随便设置,这里大了小了都会有显示的问题,读者能够尝试一下,最好的就是设置一个平均值.日志

2016-01-28 10:38:22.070 SimpleImChat[1524:58078] viewDidLoad
2016-01-28 10:38:22.071 SimpleImChat[1524:58078] viewWillAppear
2016-01-28 10:38:22.085 SimpleImChat[1524:58078] viewWillLayoutSubviews
2016-01-28 10:38:22.086 SimpleImChat[1524:58078] viewDidLayoutSubviews
2016-01-28 10:38:22.087 SimpleImChat[1524:58078] -[ChatViewController tableView:cellForRowAtIndexPath:]:0
2016-01-28 10:38:22.145 SimpleImChat[1524:58078] -[ChatViewController tableView:heightForRowAtIndexPath:]:0
2016-01-28 10:38:22.147 SimpleImChat[1524:58078] viewWillLayoutSubviews
2016-01-28 10:38:22.147 SimpleImChat[1524:58078] viewDidLayoutSubviews
2016-01-28 10:38:22.151 SimpleImChat[1524:58078] viewDidAppear

上面是设置了预估高度,而且不实现相关代理的LOG,因此,咱们看到这里的执行是很高效的,即便你频繁reload也影响不大,由于model里已经缓存了对应的cell高度.code

相关文章
相关标签/搜索