UITableView 自動計算 cell 高度並快取,再也不用管高度啦

發表於2016-11-09

這篇文章我們來講一下UITableView的cell自適應高度,以及遇到的問題的解決辦法。在看文章之前希望你已經會UITableView的基本使用了。

先奉上這篇文章的demo的Github地址:UITableViewCellHeightDemo。大家可以下載下來和文章配合看。

cell高度計算的歷史

在iOS8之前,如果UITableViewCell的高度是動態的,如果想要顯示正確的話,我們需要在下面這個UITableView的代理方法中,返回每一行的精確高度:

如果cell的控制元件很多,樣式很複雜的話,在這裡面我們就可能需要寫很多程式碼去做一些複雜的計算,甚至可能導致滑動不流暢。

後來也有一些人寫了一些第三方去解決這個問題,例如UITableView-FDTemplateLayoutCell。只要給cell自上而下加好約束,它就可以幫我們去算cell的高度並且可以快取,省去了我們自己寫計算程式碼的成本。具體可以進連結裡面看看它的demo。

但是在iOS10的系統下, FDTemplateLayoutCell會卡介面,而且tableview的行數越多表現的越卡。

而且蘋果在iOS8之後,推出了一種超級簡單的cell動態自適應的方法,使用起來比 FDTemplateLayoutCell也簡單一些,而且現在iOS10都出來了,沒有必要去支援iOS7了,所以最後我還是選擇了用系統的辦法。這樣我們以後就再也不用寫heightForRowAtIndexPath方法了哈哈哈。

系統的cell自適應高度的使用方法

首先我們需要把cell上的控制元件自上而下加好約束,如果對約束不熟悉的話建議看看下面這兩篇文章學習一下:
Auto Layout Tutorial in iOS 9 Part 1: Getting Started(http://www.raywenderlich.com/115440/auto-layout-tutorial-in-ios-9-part-1-getting-started-2)
[Auto Layout Tutorial in iOS 9 Part 2: Constraints

用xib加約束和用masonry加程式碼約束都是可以的。注意約束一定要自上而下加好,讓系統知道怎麼去計算高度。在這篇文章的demo裡面的cell加的約束是這樣的:

111608265-8e19466b6e4ac956

cell約束

加好約束後,然後告訴tableView自己去適應高度就可以了。有兩種寫法:

或者直接寫這個代理方法就可以了

這個的意思就是告訴tableView,你需要自己適應高度,我不給你算啦哈哈哈。但是我們需要告訴它一個大概高度,例如上面的100,理論上這個是可以隨便寫的,並不影響顯示結果,但是越接近真實高度越好。

來看下demo效果:

UITableView 自動計算 cell 高度並快取,再也不用管高度啦

demo

我們看到,cell已經自己適應內容算出了高度,是不是很方便呢哼哼。
具體的程式碼大家可以去demo看哦。

其實section的header和footer也是可以自動適應的,對應的方法有:

但是我們在實際開發中,一般都是根本沒有header和footer,有的話一般也是給一個固定高度。所以在這裡就不講解了,原理都一樣。

可能遇到的問題和解決辦法

1.高度不對
有時候有可能執行出來後看到cell的高度顯示的不對,就像這樣:

UITableView 自動計算 cell 高度並快取,再也不用管高度啦

高度不對

這個問題是因為約束沒有滿足自上而下,從而系統不知道怎麼去計算。解決辦法就是去修改約束,直到滿足為止。一定要好好理解約束啊!

2.點選狀態列無法滾動到頂部
我們知道,如果介面中有UIScrollView的話,點選狀態列會讓其滾動到頂部,就像這樣:

UITableView 自動計算 cell 高度並快取,再也不用管高度啦

點選狀態列會滾動到頂部

但是如果我們用了自動計算高度的方法,又呼叫了tableView的reloadData方法(例如我們的資料有分頁的時候,載入完下一頁的資料後會去重新整理tableView)。這時候就會出現問題,點選狀態列就有機率不能精確滾動到頂部了:

解決這個問題的辦法是去快取cell的高度,程式碼如下:

解釋一下,就是用一個字典做容器,在cell將要顯示的時候在字典中儲存這行cell的高度。然後在呼叫estimatedHeightForRowAtIndexPath方法時,先去字典檢視有沒有快取高度,有就返回,沒有就返回一個大概高度。

快取高度之後,在demo裡面多試幾次,發現點選狀態列已經可以精確滾動回頂部了:

UITableView 自動計算 cell 高度並快取,再也不用管高度啦

用快取高度解決了問題

這段程式碼其實可以寫在viewController的基類裡面,這樣寫一遍就可以每個地方都能快取cell的高度了。詳見demo。這樣就完美了!

好啦先說到這裡吧,有問題記得聯絡我。

相關文章