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

相關文章
相關標籤/搜索