當前位置:
首頁 > 最新 > UITableViewCell 高度自適應牽扯出的若干問題

UITableViewCell 高度自適應牽扯出的若干問題

闊別了一年寫代碼的感覺,工作以來一直從事產品經理的相關工作,最近開始尋找當年寫代碼的感覺。碰巧上來被一個原以為很簡單的問題困擾了很久,下面給大家詳細講講使用 Self-Sizing Cell 做高度自適應遇到的若干坑。

Self-Sizing Cell

Self-Sizing 是 Apple 在 iOS 8 之後推出的新技術,是用於在調整系統字體大小後,控制項元素中的文字能跟自動使用布局,下圖所示的就是配合 Self-Sizing 推出的系統修改字體。

在 iOS8 以前,決定 tableviewcell 的高度的都是 ,在該方法中手動計算 cell 的高度。iOS 8 之後,Apple 推出了新技術 Self-Sizing,通過 Working with Self-Sizing Tableview cells,將 cell 和 Self-Sizing 進行配合使用後這個協議函數就不用管了,高度系統會自動進行計算。具體的實現方式如下:

Step One

通過 StoryBoard 新建 Custom TableView Cell,並且把要自適應文本高度的 UILabel 添加上約束。約束的原則如果上下左右沒有其他元素,直接和 SuperView 做相對約束,如果有其他元素,則其他元素需要布局確定,UILabel 做相對約束。注意很重要的一點,最後 UILabel 的約束最後對寬和高都沒有做約束,只有上下左右四邊的約束看,這樣的 Cell 才可以進行高度自適應。

Step Two

在代碼中添加兩個方法,接下來載入出數據的時候就可以自動計算高度。

override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 100//估算高度儘可能的接近 cell 的高度 }由此引發的問題1.willDisplayCell:forRowAtIndexPath: and cellForRowAtIndexPath:

在關於優化 UITableView 的文章中,提到了一個優化方案。

我們經常在注意cellForRowAtIndexPath:中為每一個cell綁定數據,實際上在調用cellForRowAtIndexPath:的時候cell還沒有被顯示出來,為了提高效率我們應該把數據綁定的操作放在cell顯示出來後再執行,可以在tableView:willDisplayCell:forRowAtIndexPath:方法中綁定數據。

我剛剛開始對這個觀點是認可,並且也確實這麼做了,於是代碼如下:

func tableView(_tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell: CustomCell = tableView.dequeueReusableCell() return cell } func tableView(_tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let cell = cell as? CustomCell else { return } cell.titleLabel.text = Json.desc return }

在執行上述代碼之後,我發現了一個問題,UITableViewCell 的高度載入並不正確,是估算的高度,並不是計算的高度,如下圖。

滑動之後新載入的 TableViewCell 高度為計算出來且正確。(繼承 UITableViewViewController 即 Delegate and DataSource 方法為 override 可以滑動載入正確高度;而繼承自 UIViewController 即 Delegate and DataSource 方法是 extension 滑動也不可以載入正確高度。注意,後面的繼承未寫 Demo 論證,若有不對請指出

從上面的問題裡面,我開始尋找兩個方法的作用和遇到類似問題的解答方式,我在 Stack Overflow 上面找到了類似的問題UITableView cellForRowAt vs willDisplay。上面闡述的解釋是高度的計算是在 之後,在 之前,所以需要再次調用 方法。

My understanding that at height is calculating after cellForRowAt but before willDisplay, so when I』m mapping in willDisplay height is already set for my cell and I need to reload it again (which is not good).

這個結論我是認同,所以解決這個問題的辦法就有兩個方案。

將數據綁定從 中移到 中;

再次調用 放大,代碼如下:

self.tableView.reloadData() // 3 new lines of codes to force size adjustment self.tableView.setNeedsLayout() self.tableView.layoutIfNeeded() self.tableView.reloadData()

上述兩個方案,第二個方案是強制高度自適應,具體可以參考這邊文章Swift: How to Resize UITextView + TableViewCell Correctly After JSON Fetch,但是這個方法顯得很臃腫,也並不能算是優雅的解決方案。於是我看到第一個方案時產生了疑問:

【為了提高效率我們應該把數據綁定的操作放在 cell 顯示出來後再執行】這個觀點是正確的嗎?

數據綁定應該放在哪兒?

我們首先看下蘋果官方文檔關於 的解釋,該方法應該是修改狀態類型基本屬性,比如選擇狀態、背景顏色等等:

This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color.

官方文檔關於 的解釋,該方法應該是講數據源插入到 UITableView 正確的位置:

Asks the data source for a cell to insert in a particular location of the table view.

在此同時,我看到了一篇詳細的文章Proper Use of CellForRowAtIndexPath and WillDisplayCell,文章中指出:

Orlov』s article is an important guide for advanced programming. However, he is lacking proof for the tableView delegate method willDisplayCell:forRowAtIndexPath:. This has been something that has bothered me for a while, as so many people quoted the paragraph about willDisplayCell from the article.

很重要的一句話,並沒有任何理由能夠支持他說的綁定數據在 willDisplayCell 能夠提高 UITableView 的性能。並且他做了實驗,發現 是在 和 兩個方法之後,也就是說不管你在哪個方法中去綁定數據,cell 被 layouted 總在他們之後,那麼在這之前就不會 Rendering,也就不存在綁定數據在 方法中會影響性能。

那麼,這個優化方案並沒有任何理論根據,於是忘了吧,

注意,關於 Orlov』s article 雖然提升這一點沒有被佐證,但是其他的優化方案非常值得學習,我這邊附上鏈接,有興趣可以學習!注意使用梯子~~文章:perfect smooth scrolling in uitableviews

自動計算載入了幾次?

本來到這邊應該結束文章,但是在探討上述問題的時候,發現了很奇怪的一件事情。如果你在 UITableView Delegate 或者 DataSource 方法中列印一下,會發現每個方法中的列印出現了2遍。

於是,我參考了兩篇文章:scrollViewDidScroll is called 「twice」 after set table offset、heightForRowAtIndexPath called twice in iOS 8 but one time in iOS 7

這句話是引起 UITableView 載入兩次的原因,注釋掉這句話後,發現列印一次。我並沒有找到合理的解釋去解釋這個原因,網上部分猜測是 Apple 官方的 Bug,如果大家對這個問題有合理的解釋,不妨聯繫我。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

喜歡的人開始秒回微信,卻發現所有話題都很快被聊死
C#的「友元」類實現 Builder 模式
即學即用,網頁首屏頁面7種吸睛的設計方法
vue-cli定製腳手架
Orbit框架解析

TAG:推酷 |

您可能感興趣

Bitfinex和Tether牽扯不清,1:1錨定美元的USDT是否只是「空氣幣」?
知情人透露 Diddy 計劃「處理」Eminem 牽扯其涉入 Tupac 買兇事件
王健林攪局區塊鏈?萬達:先與Centrality技術合作,不牽扯任何ICO
吳亦凡diss還沒結束,MC光光aka發文支持,這次居然牽扯到GAI
都是韓瑞熙的錯?iKon金韓彬吸毒,Winner李昇勛遭牽扯
Facebook數據泄露門牽扯4家中國公司 華為與聯想上榜
FaceBook數據泄密背後牽扯出了一個關於隱私、廣告和總統競選的離奇故事
The Weeknd複合後首度牽手女友,貝拉的腰惹人羨慕,賽琳娜受牽扯
蘋果、國產安卓,不牽扯到愛國層面,更願意選擇iPhone手機
節目報女團T-ara不實新聞,牽扯到王思聰,如今公開道歉
節目報女團T-ara不實新聞,還牽扯到王思聰,如今公開道歉
RNG運營體系更加成熟,牽扯打法2:0帶走TOP,粉絲段子笑哭我了
三局完美運營牽扯 BLG橫掃RNG晉級下一輪
打野Condi處罰結果公布,之前所說全部為謊言,順帶牽扯另外三人
漫威DC電影中那些讓人不敢深思的細節盤點:牽扯時間線都是BUG
潘長江被罵升級,雖然微博道歉,但潘陽也被ikun強行牽扯其中
王源風波被牽扯的人越來越多,連TFBOYS周年和生日的煙盒都被扒出!
「勝利事件」一再發酵:牽扯出柯震東,INS發文稱「世界殘酷」
ZICO否認牽扯「鄭俊英醜聞」,多名相關藝人也發文聲稱無關!
引人深思人性圖:我的「全家福」,網路的牽扯,方便or害人?