Storyboard中用Auto Layout的“Bug”
在storyboard中使用自動布局,根控制器為一個UITableView邑彪,所有的cell的行高根據(jù)cell內(nèi)容的多少動態(tài)變化(類似微博惋戏、微信朋友圈等應(yīng)用)沟蔑。
鏈接地址:demo
據(jù)此居触,我根據(jù)
Cell
的內(nèi)容獲取Cell
內(nèi)的label
和UIImageView
的frame馅而,然后在layoutSubview方法中根據(jù)frame來計算最終的行高,然后黍聂,在controller中通過代理方法拿到行高。
這是很常規(guī)的一個開發(fā)思路身腻,可是在storyboard開發(fā)中使用prototype(原型)cell的方式來實現(xiàn)卻遇到了問題...
1.首先产还,我在StoryBoard里面使用prototype(原型)cell,而且沒有改ViewController屬性檢測器中的simulation Metrics
的size
<img src="http://upload-images.jianshu.io/upload_images/2473291-318b2b21411c5051.png" width="400" height="400" alt="不設(shè)置此處的尺寸"/>
2.然后嘀趟,我給cell中的所有的子控件設(shè)置了約束脐区,并且確認(rèn)無誤,沒有警告和錯誤她按,然后我update了一下所有控件的frame(注意:這里如果不更新所有控件的frame的話牛隅,storyboard便會給你報黃色警告炕柔,提示你期望的大小和真實的大小不相同,截圖如下
<img src="http://upload-images.jianshu.io/upload_images/2473291-2a660988870a8925.png" width="400" height="300" alt="ExpectedFrame和ActualFrame的警告"/>
3.解決上面的辦法也很簡單媒佣,點擊警報匕累,點擊Fix(修復(fù))或者選中所有的控件,點擊下方設(shè)置約束按鈕中最右邊的一個默伍,選擇"Update Frame"就可以了
<img src="http://upload-images.jianshu.io/upload_images/2473291-3292bacfb3423660.png" width="400" height="400" alt="修復(fù)上述警報的沖突"/>
4.設(shè)置完約束欢嘿,我需要分別實現(xiàn)模型中的邏輯,和自定義的cell中的邏輯
4.1. 模型類從網(wǎng)絡(luò)獲取數(shù)據(jù)右锨,使用的是異步子線程蛋勺,下載完成后回調(diào)颓遏,切換主線程給ViewController中的數(shù)據(jù)數(shù)組賦值。
4.2. 給自定的cell內(nèi)的子控件賦值寫在了
UITableViewDatasource
的返回cell的方法中掐隐,但是,要求cell內(nèi)的副標(biāo)題Label的顯示或不顯示钞馁,取決于主標(biāo)題Label的行數(shù)虑省,如果主標(biāo)題只顯示1行,那么就顯示副標(biāo)題指攒,相反慷妙,就不顯示副標(biāo)題。
這個邏輯才是重點
我在cell的layoutSubviews
方法中獲取主標(biāo)題的frame允悦,可是膝擂,無論如何改變主標(biāo)題Label的約束,通過layoutSubviews
方法獲取到的frame始終不變隙弛。這里引起了我的懷疑架馋,因為layoutSubviews
方法的解釋是當(dāng)父控件的frame發(fā)生改變的時候,會調(diào)用此方法全闷。但是實際來看在layoutSubviews
方法中cell內(nèi)的控件的frame仍然未發(fā)生變化叉寂,還是storyboard中Update Frames之后的值!!
但是當(dāng)執(zhí)行完
layoutSubviews
方法后,界面就已經(jīng)能夠正常地顯示出來了总珠,并且大小都正常屏鳍,但是在layoutSubviews
方法里打印的Label的frame卻不正確,這就很奇怪局服!
于是钓瞭,我繼續(xù)猜想,這可能是由于約束設(shè)置完成之后淫奔,需要通過很多計算山涡,而產(chǎn)生一個時間差,所以就使得在layoutSubviews
方法執(zhí)行的那一瞬間,無法立即計算出主標(biāo)題的正確的frame鸭丛。
接著竞穷,我尋找其他的思路,發(fā)現(xiàn)有一個方法layoutIfNeeded
鳞溉,這個方法的解釋是:Lays out the subviews immediately.在調(diào)用這個方法后瘾带,立即布局該控件的子控件,因此穿挨,我試著在調(diào)用主標(biāo)題Label的getter方法之前月弛,調(diào)用layoutIfNeeded
這個方法,結(jié)果就成功了科盛。
得出總結(jié):當(dāng)父控件的frame發(fā)生變化的時候,會調(diào)用它的layoutSubviews
方法帽衙,但是,此時我們的約束還沒有計算好所有子控件的frame值贞绵,所以厉萝,要在layoutSubviews
方法內(nèi)獲取子控件的frame,可能就會拿到一個錯誤的frame值
在解決這個Bug的同時榨崩,還遇到一個小插曲谴垫,當(dāng)屬性檢測器使用的是默認(rèn)的大小的時候,如果勾選了storyboard中的ViewController屬性檢測器的Refreshing中的Enabled選項母蛛,則會出現(xiàn)在剛開始進(jìn)入應(yīng)用的時候翩剪,就會加載self.refreshControl 的title 內(nèi)容
但是當(dāng)我不進(jìn)行其他任何的操作,而僅僅只是把屬性檢測器中模擬器的size屬性設(shè)置為一個其他的大小時彩郊,就不會有上述的效果了