使用Autolayout實現UITableView的Cell動態布局和高度動態改變

核心概念

不管你是在哪個iOS版本上做開發,以下步驟中的前兩個步驟都是必須的:

1、設置好布局約束條件

在UITableViewCell子類中,添加布局約束,使得cell子視圖的邊緣固定(pin)到cell的contentView的邊緣(最重要的是要有頂部和底部的邊距約束條件)。注意:不要將子視圖的邊距約束固定到cell本身上了,只能固定到cell的contentView上! 確保每個子視圖垂直方向上的內容壓縮阻力(compression resistance)和吸附性約束(hugging constraints)沒有被你添加的更高優先級的約束條件覆蓋,讓這些子視圖的固有內容尺寸(intrinsic content size)來驅動contentView的高度。(沒看懂?點這里。)

記住,要點是讓cell的子視圖與contentView之間產生垂直的連結,讓它們能夠對contentView“施加壓力”,使contentView擴展以適合它們的尺寸。下面用一個cell和一些子視圖作為示例,展示了你的一些(不是全部!)布局約束應該看起來是什么樣的:


2. Cell使用具有唯一性的重用標示符

在cell里面,為每一組特定的約束條件,使用一個特定的cell重用標示符。換句話說,如果cell有多種不同的布局,每一種布局應當有其對應的重用標示符。(當cell有多種不同數量的子視圖的時候,或者子視圖以一種獨特的方式布局的時候,這些情況下你就需要使用一個新的重用標示符。)

例如,要在一個cell中顯示一條email消息,可能會有4種獨特的布局:第一種,只有主題的消息;第二種,帶主題和正文的消息;第三種,帶主題和圖片附件的消息;第四種,帶主題、正文和圖片附件的消息。每一種布局都需要完全不同的布局約束才能實現。因此,一旦cell被初始化并且布局約束被加到其中任意一種類型的cell上后,cell應當得到一個唯一的重用標示符來指定該cell類型。這就意味著,當你dequeue重用一個cell的時候,該類型cell的布局約束已經添加好了,可以直接使用。

注意,由于固有內容尺寸的不同,具有相同布局約束的cell仍然可能具有不同的高度!不要混淆了布局(不同的約束)和由不同內容尺寸而計算出(通過相同的布局約束來計算)的不同視圖frame這兩個概念,它們根本是完全不同的兩個東西。


3. 啟用估算行高

在iOS8上,蘋果將許多在iOS8之前比較難實現的東西都內置實現了。為了讓cell實現self-sizing的機制,必須先將tableView的rowHeight屬性設置為常量UITableViewAutomaticDimension。然后,只需將tableView的estimatedRowHeight屬性設置為非零值即可開啟行高估算功能。

這樣做就為tableView上還沒有顯示在屏幕上的cell提供了一個臨時的估算的行高。然后,當cell即將滾入屏幕范圍內的時候,會計算出實際的高度。為了確定每一行的實際高度,tableView會自動讓每個cell基于其contentView的已知固定寬度(tableView的寬度,減去其他額外的,像section index或accessoryView這些寬度)和被加到contentView及其子視圖上的自動布局約束規則來計算contentView的高度。一旦真正的行高被計算出來后,舊的估算的行高會被更新為這個真實的行高(并且其他任何需要對tableView的contentSize或contentOffset的更改都自動替你完成了)。

一般來說,行高估算值不需要太精確——它只是被用來修正tableView中滾動條的大小的,當你在屏幕上滑動cell的時候,即便估算值不準確,tableView還是能很好地調節滾動條。將tableView的estimatedRowHeight屬性設置成(在viewDidLoad或類似的方法中)一個接近于“平均”行高的常量值即可。只有行高變化很極端的時候(比如相差一個數量級),才會在滾動時產生滾動條“跳躍”的現象。這個時候,你才應當實現tableView:estimatedHeightForRowAtIndexPath:方法,為每一行返回一個更精確的估算值。

4. 完成一個完整的布局過程 & 計算cell的高度

首先,為每一個cell都初始化一個離屏(offscreen)實例,為每個重用標示符實例化一個與之對應的cell實例,這些cell完全用于高度計算。(離屏表示cell的引用被存儲在view controller的一個屬性或實例變量之中,并且這個cell絕對不會被用作tableView:cellForRowAtIndexPath:方法的返回值以實際呈現在屏幕上。)接著,這個cell的內容(例如,文本、圖片等等)還必須和會被顯示在table view中的內容完全一致。

然后,強制cell立即更新子視圖的布局,再用cell的contentView調用systemLayoutSizeFittingSize:方法計算出cell所需的高度是多少。使用UILayoutFittingCompressedSize參數可以得到適合cell中所有內容所需的最小尺寸。然后其高度就可以作為tableView:heightForRowAtIndexPath:方法的返回值

5. 緩存行高(如果需要)

如果上面提到的你都做了,但是tableView:heightForRowAtIndexPath:的性能仍然慢的不可接受。非常不幸,你需要給行高做一些緩存(這是蘋果的工程師們給出的改進建議)。大體的思路是,第一次計算時讓自動布局引擎解析約束條件,然后將計算出的行高緩存起來,以后所有對該cell的高度的請求都返回緩存值。當然,關鍵還要確保任何會導致cell高度變化的情況發生時你都清除了緩存的行高——這通常發生在cell的內容變化時或其他重大事件發生時(比如用戶調節了動態類型文本大小(Dynamic Type text size)的滑動條)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容