準(zhǔn)備知識
intrinsic Content Size, 內(nèi)建大小.
控件的內(nèi)置屬性. 像 UILabel 會根據(jù)自己顯示的 text 得出一個 intrinsic size. 普通的 UIView 的 intrinsic content size 的屬性都為 0. 可以通過 ovrride 的方式去設(shè)置自定義 View 的 intrinsic content size.
優(yōu)先級
iOS 當(dāng)中的每一個約束都有一個優(yōu)先級. 當(dāng)兩個約束沖突的時候系統(tǒng)會選擇破壞優(yōu)先級比較低的約束. 如果兩個優(yōu)先級一樣, 那么系統(tǒng)就會隨機(jī)地選擇一個優(yōu)先級, 并拋出一個錯誤:
常見默認(rèn)的優(yōu)先級有, 251(CH屬性), 750(CR屬性), 1000(其他約束). 雖然理論上來說優(yōu)先級只要是 0 ~ 1000 之間的整數(shù)都可以. 但是為了方便, 我們通常只有用比默認(rèn)屬性小 1 的優(yōu)先級, 比如 250, 749, 999.
CHCR 屬性
前面說到有一些控件擁有自己的 intrinsic content size. intrinsic content size 其實(shí)也是一種特殊的約束. 是約束就有優(yōu)先級. 但是跟普通的約束不同, 對 intrinsic size 的破壞分為兩種, 擴(kuò)大和壓縮. 所以 intrinsic size 的優(yōu)先級是由兩個部分組成的. 分為別 Content hugging Priority 和 Compression Resistance Priority.
- CH: Content Hugging Priority.
當(dāng)需要擴(kuò)大 intrinsic size 時使用的 priority. 該屬性越高, 控件越不會被拉伸. 默認(rèn)的優(yōu)先級是251 - CR: Compression Resistance.
當(dāng)需要縮小 intrinsic size 時使用的 priority. 該屬性越高, 控件越不會被壓縮. 默認(rèn)的優(yōu)先級是750
問題
最近要在 UITableView 是實(shí)現(xiàn)一個 Cell 折疊和展開的效果. 基本的思路就是通過 UITableView 的自適應(yīng)機(jī)制, 通過改變約束的高度來改變, 然后通過 TableView 進(jìn)行update. 簡單實(shí)現(xiàn)后, 功能倒是沒有問題. 但是中間的動畫卻不是期待的樣子.
做了一個 Demo 演示效果.
約束非常簡單, Cell 里面有一個 UILabel. Label 有 Top 和 Bottom 的約束, Cell 的高度是自適應(yīng)的. 當(dāng)點(diǎn)擊按鈕的時候會調(diào)整 BottomContraints 的數(shù)值來實(shí)現(xiàn)高度變化.
實(shí)現(xiàn)的效果如下:
可以看到在擴(kuò)大和縮小的時候 Test 2 文字有明顯的跳動. 原因在于變化瞬間, 雖然 bottom constraint 的數(shù)值發(fā)生了改變, 但是 Cell 高度還沒有發(fā)生改變. 所以這個時候不能滿足所有的約束, 那么會選擇破壞一個優(yōu)先級最低的約束. 在垂直方向, 優(yōu)先級最低的約束就是 Label 的 intrinsic conttent size. 所以在縮小時系統(tǒng)選擇擴(kuò)大了 Label 的大小, 因?yàn)槲淖质蔷又械? 所以會看到文字的跳動.
從我們的需求的來說, 我們希望系統(tǒng)破壞的是 bottom 的約束. 想到達(dá)到這個這個目的, 我們只需要將 bottom 的優(yōu)先級設(shè)成比 Label 的Content Hugging Priority 更低就可以了. 將 bottom 的優(yōu)先級設(shè)成250 以后的效果如圖:
Demo 的地址: https://github.com/Guaidaodl/iOS-Demos