為什么出現一種約束叫做 NSIBPrototypingLayoutConstraint
一般來講,約束的類型應該都是 NSLayoutConstraint,但是從 Xcode 4 開始,增加了 Auto Layout 功能時,考慮到當開發者在 IB 中創建 View 后,沒有顯示的主動添加任何約束,會導致視圖無法顯示,因此 IB 會根據你拖動 View 的位置,自動的幫你加上約束,避免視圖無法顯示,因為這種約束是 IB 自動添加的,因此類名叫 NSIBPrototypingLayoutConstraint,并且這種約束無法通過 NSLog(@"%@", self.constraints);
打印出來。
深層次的原因
一般來講,這種情況下,對當前 View 設置
view.translatesAutoresizingMaskIntoConstraints = NO;
即可。
對于 translatesAutoresizingMaskIntoConstraints
屬性,官方文檔時這樣寫的:
Discussion
If this property’s value is YES, the system creates a set of constraints that duplicate the behavior specified by the view’s autoresizing mask. This also lets you modify the view’s size and location using the view’s frame, bounds, or center properties, allowing you to create a static, frame-based layout within Auto Layout.
Note that the autoresizing mask constraints fully specify the view’s size and position; therefore, you cannot add additional constraints to modify this size or position without introducing conflicts. If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set this property to NO, and then provide a nonambiguous, nonconflicting set of constraints for the view.
By default, the property is set to YES for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to NO.
簡單翻譯一下,意思是說:
使用代碼創建 View 時,這個屬性默認是 YES,然后你就可以通過設置其 frame、bounds、center 等屬性,自動的轉換為 autoLayout 的約束。保證視圖約束的完整性,能夠很好的顯示。
但是,你一旦這么做了,那么就不能額外給這個 View 添加約束了。因為,這個 View 已經有了 transfer 過來的約束,你再添加的話,約束將會沖突。
如果你希望能夠手動地添加約束,來滿足需求,那么就需要設置 translatesAutoresizingMaskIntoConstraints = NO
。
在使用 IB 時,這個屬性默認是 NO。
一點疑惑
官方的說法中,在 IB 中,這個屬性應該是 NO,但是我通過 xib 創建的 UITableViewCell ,在awakeFromNib
方法中,打印出該屬性是 YES。
就是因為這樣,才導致我在awakeFromNib
方法中使用 masonry 添加的約束有了沖突。
解決問題的最終辦法
在 IB 中,顯示的為 view 添加一些約束,然后全部選擇這些約束,在 File Inspector
中,勾選 Remove at build time
;
為什么上述方法可以解決問題
問題的根本是 IB 自動創建了我們不想要的約束,IB 自動創建的原因是 view 上沒有約束,因此我們隨意給 view 添加一些無用的約束,然后讓其在 building 時刪除掉。
這樣子,當代碼執行到 masonry make 創建約束時,這個 view 將是一個干凈的 view。
Placeholder : Remove At build time
這個屬性呢,其實本來的使用場景是這樣:
在開發過程中,有時候需要預覽一些布局,那么在 Storyboard 上添加約束,就會很方便,這樣子在不執行代碼的情況下,就能夠測試驗證我們的約束是否正確。
但是呢,在實際開發中,很可能大家覺得在 storyboard 上添加約束比較麻煩,團隊之間協作不好,因此希望能夠使用代碼創建約束,比如 masonry 這種工具。
很簡單,只需要在運行時,將 storyboard 中添加的約束全部刪除掉。這樣子,storyboard 中添加的約束不會對代碼添加的約束造成任何影響。另一方面,在 storyboard 中布局可以更加方便,且 storyboard 中不會出現一堆關于約束的 warning。
后記
有什么問題,可以留言,我會盡快回復~