最近作項目時,由於iPhone6和iPhone6Plus的兼容,咱們啓用了Autolayout. 之前是由於不用也能知足需求,也是由於懶,沒有認真使用,只是瞭解過。通過一段時間的使用,作下總結,但願給你們些幫助哈。html
之前我寫過IOS自動佈局之Autoresizing是關於Autoresizing的介紹,在簡單的佈局上比較有用,今天總結的是更強大的Autolayout.ios
本文不是從零開始入門級的介紹,主要介紹了學習過程當中遇到一些問題的解決方案,但願給你們幫助,若是初學者請先看看蘋果文檔,玩玩Autolayout.git
PS: Autolayout的強大是毋庸質疑的,當你熟悉了它以後,你確定會喜歡上它,佈局將會比使用frame的絕對座標時還方便。若是尚未用Autolayout,這已是最後的時機啦,再不學就out了。github
仍是先介紹下咱們能夠用哪些途徑來使用Autolayout吧,這裏只作介紹,具體如何使用,你們能夠點擊對應連接進入文檔學習。app
最直觀的使用就是在xib文件中使用Autolayout. 這種方式最直觀,初學者建議先在xib中拖一拖,創建佈局的概念。框架
這是一個第三方的很是好用的開源框架,之前我覺得Autolayout只能用xib了,不然代碼量太大了,可是Masonry讓用代碼寫Autolayout成爲可能,並且很是強大,清晰好用,示例:iphone
12345678 |
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);[view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right);}]; |
這是蘋果推出的一種在代碼中使用Autolayout的語法,使用特定的string來建立Constraint,如[button]-[textField]
表明button和textField間隔標準間距(通常是8) Virtual Format Language 我的感受沒有Masonry好理解和使用。佈局
Autolayout的本質就是經過給view添加約束,系統經過這些約束來計算view的真實frame. 約束就是類NSLayoutConstraint
的實例。這裏牽涉到Constraint的原理,稍做解釋下,理解原理對學習老是好的。那麼,什麼是Constraint呢? 看下面的公式:學習
y = m ∙ x + b優化
每個NSLayoutConstraint
都表明了上面的這個關係式,其中:
x, y 表明view的attribute, attribute能夠分爲left right top bottom leading trailing width height centerX centerY baseline m 是倍數, 即multiplier b 常數, 即 constant
從這個公式咱們能夠了解咱們在建立Constraint時,設置的值是如何工做的,好比: x表明 view1.width, y表明view2.width, m = 2, b = 0; 這個約束就表明view2的寬是view1的2倍。
從公式中也能夠了解到Constraint只能表明線性關閉,不過只是佈局貌似不必更復雜的關係吧。
有沒有發現attribute中有了left和right, 可是還有leading和trailing. 用過的同窗會發現這兩對沒啥區別,爲何會有這2種呢,緣由是否是世界上全部的文字都是從left到right。 若是文字是從右到左的話,leading就對應right, training就對應left了。
手動建立Constraint的API:
1234567 |
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c; |
理解了上面的公式,再看這個API是否是不同了呢。
經過分析,咱們決定採用前兩種方式來進行Autolayout的開發。因此不管你是否是代碼黨,均可以玩轉Autolayout哦。
當咱們使用Autoresizing時,運行時會自動根據autoresizingMask的特性爲view添加Constraint, 咱們能夠經過下面這個API來決定啓用仍是關閉這一特性(NO爲關閉):
1 |
- (void)setTranslatesAutoresizingMaskIntoConstraints:(BOOL)flag NS_AVAILABLE_IOS(6_0); |
這個屬性在xib中默認是NO, 在不用xib時默認是YES, 也就是若是使用代碼建立Constraint時,須要設置該屬性爲NO, Masonry
自動幫咱們作了這一操做,因此用Masonry
不須要設置改屬性。
在xib中設置Constraint時,你會看到這塊:
在UIView的API中也能夠看到這幾個方法:
1234 |
- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0); |
那麼這兩個東西究竟是什麼呢?能夠這樣形象的理解一下:
contentHugging: 抱住使其在「內容大小」的基礎上不能繼續變大 contentCompression: 撐住使其在在其「內容大小」的基礎上不能繼續變小
這兩個屬性分別能夠設置水平方向和垂直方向上的,並且一個默認優先級是250, 一個默認優先級是750. 由於這兩個頗有可能與其餘Constraint衝突,因此優先級較低。
設置Constraint的過程其實就是作算術題的過程,這裏提醒你們, xib中有Suggest Constraint的功能,可是你們不要用,特別是在學習Autolayout階段,Suggest Constraint自動補全的Constraint通常不能直接用,除非你view不多。
若是設置Constraint來肯定一個view的frame呢,你能夠裏面想到: * 1. frame法,像定義frame同樣定義約束,就是設置view.left view.top view.width view.height. 可是實際中不多這樣用。 * 2. edge法, 設置 view.left view.top view.bottom view.right。 * 3. 居中法, 設置 centerX centerY width height.
等等方法,然而事實使用中你可能不是隻有一個view,有可能有不少的view,相互直接會有不少的約束,約束一多就會容易發生邏輯衝突,這個時候就會發現Constraint優先級的做用了。
Constraint還有個屬性叫priority, 即優先級,通常是0 ~ 1000之間的整數。 1000表明是必需的, 0則不會生效。理解和使用好優先級是熟練使用Autolayout所必備的。
舉個栗子, UITableViewCell
會默認設置 cell.height
這個約束, 若是你像上圖中設置了垂直方向上的Constraint,在IOS7上是有crash的風險的哦。下面講緣由:
label1.top + label1.height + (label1-label2) + lable2.height +label2.bottom ≠ cell.height
若是上面不等式發生,那麼就會產生Constraint衝突,在IOS8上,蘋果應該作了優化,不會crash,只是在控制檯會報警告,在IOS7上就會crash了。
啥,你說這些值你都提早算正確就不會出問題了? 不要太自信,還有一種東西叫「浮點值不許」。 因此最好儘可能避免這樣的衝突,解決方案也很簡單: 選擇一個constraint下降優先級,好比把label2.bottom的優先級調到 998. 這樣就解決了約束衝突的問題,當約束髮生衝突時,低優先級的約束會被捨棄。
假設在同一水平方向上平行的 Label1 和 Label2。當在水平屏幕寬度不足以展現兩個Label的所有內容時,怎麼決定哪一個Label先展現不全呢,就是經過設置起contentCompression的水平方向上的優先級就能夠解決。好比當 Label1.contentCompression < Label2.contentCompression 時, 那麼Label1就會展現爲 「內容…」 這種。
Autolayout看再多的教程資料不如本身動手一試,因此本文不作詳細介紹,旨在分析理解和問題。 (一)就到這吧, 下一篇將會介紹 《自動適應高度Label和Cell的方案》, 《如何在ScrollView中使用Autolayout》, 《Autolayout時的動畫》。