iOS AutoLayout還可以這樣玩

Auto Layout
網上關于 Auto Layout 的文章繁多, 但是總覺得有些內容并沒有說清楚。所以在這篇文章里,我將通過一個demo演示 Auto Layout 中幾個容易被忽略,但是又相當重要的概念
demo效果

demo效果
demo 中要通過約束要實現的效果如下:
- backgroundView width>=60;
- backgroundView的width隨著Label中內容的增加而增加
- backgroundView與其superView的margin>=30。也就是當Label的內容過長時,會顯示出省略號。
概念
要實現demo 中的效果前,需要知道下面的幾個概念:
1, Constraint equalities (暫且叫做約束等式):這個就是常見的約束類型。不再贅述,舉幾個例子:
Red.top = 1.0 * Superview.top + 20.0
Superview.bottom = 1.0 * Red.bottom + 20.0
Red.top = 1.0 * Blue.top + 0.0
Red.bottom = 1.0 * Blue.bottom + 0.0
2, Constraint Inequalities (暫且叫做約束不等式):它指定一個區域而不是一個確切的值。
// Setting the minimum width
View.width >= 0.0 * NotAnAttribute + 40.0
// Setting the maximum width
View.width <= 0.0 * NotAnAttribute + 280.0
3, Constraint Priorities 約束優先級 : 約束優級是一個0-1000的數值。當兩個約束出現沖突時,優先級高的約束將保留,優先級低的約束失效。
4, Intrinsic Content Size 內在內容size: 有些view 可以根據其內容設定其size。比如說UILabel,UIButton等,他們的size剛好能夠容納其內容支持 Intrinsic Content Size 的view如下:

Intrinsic Content Size
5, content-hugging priorities 抗拉伸優先級(默認250) :這個優先級與 Intrinsic Content Size 相關。假如一個Label的 Intrinsic Content Size width=50, 現在添加一個width=60的約束(默認優先級是1000)現在Label就會拉伸 。如果將 約束width=60的優先級設置成小于250的值,Label就不會被拉伸。
6, compression-resistance priorities 抗壓縮優先級(默認750):這個優先級也與 Intrinsic Content Size 相關。假如一個Label的 Intrinsic Content Size width=50, 現在添加一個width=40的約束(默認優先級是1000)現在Label就會壓縮 。如果將 約束width=40的優先級設置成小于750的值,Label就不會被壓縮。 可以看出 content-hugging priorities 和 compression-resistance priorities 用于抵抗其他約束對view Intrinsic Content Size 的改變。
實戰
介紹完上面的概念,讓我們使用他們完成上面demo效果。
1, 新建工程,打開storyboard。添加backgroundView(繼承自UIView), 設置背景顏色為灰色并添加 水平居中和垂直居中約束。此時會出現約束錯誤,這是因為這個backgroundView只設置了position,沒有設置size。 不必擔心,一會就可解決這個問題;
約束如下:

pic1

pic2
2, 在backgroundView中添加一個 ActivityIndicatorView 和 Label。(下面還添加了一個button, 當點擊下面的button時,label中的內容會增加)
view層級關系如下:

pic3
添加下列約束:

pic4

pic5
此時的約束沒有任何錯誤了顯示效果如下:

pic6
3, 此時通過給Label添加文字,backgroundView也會相應增大(只分析水平方向)。為什么增大? 這是因為Label的text決定 Intrinsic Content Size 的大小, text增多, Intrinsic Content Size 相應增加。Label與backgroundView 的margin為10。所以根據這一系列的關系導致了 給Label添加文字,backgroundView也會相應增大。

pic7
4, 現在有個問題, 當label中的文字太多時,backgroundView的寬度會超出其父view范圍,這顯然不太好。添加一個約束使backgroundView與其父view之間有一個最小的margin。 這時就要使用約束不等式了。約束不等式可以指定一個范圍而不是一個確切的數值。看下面的例子。

pic8
添加如下約束, 這樣backgroundView和superView 之間的margin最小是30。當label中的內容過長時,內容就會被壓縮。But Why?

pic9

pic10
5 , backgroundView 的width隨Label中內容的增加而增加。 當backgroundView 與其superView 的margin=30后,再增加 backgroundView 的width就會產生約束沖突了(與之前設置的 ‘backgroundView和superView 之間的margin最小是30’ 這條約束產生沖突 )。那么stroyboard是如何解決沖突的那? 對,就是優先級。
‘backgroundView和superView 之間的margin最小是30’這條約束的優先級時1000, 是最大優先級。 Label 的抗壓縮優先級默認750,1000>750, Label這能被壓縮了(內容省略了一部分)。如果你將這兩個優先級大小交換一下,backgroundView與superView 就之間不會出現margin了。
6, 當label中有一個字母是, 效果是這樣的。 好丑。。。。

pic11
我們給backgroundView設置一個最小width約束。 我們設置backgroundView的width =60約束, 并設置優先級996。(當然,你也可以使用width >=60這樣的約束。這里為了演示優先級)
現在的效果是這個樣子的:

pic12
又出問題了。。。 雖然backgroundView width=60確實起作用了,但是Label內容增加時backgroundView的width并沒有增加。這還是優先級的問題。Label 的抗壓縮優先級是750, backgroundView width=60的優先級時996,996>750, 當然會出問題了。 現在只需讓 Label的抗壓縮優先級大于backgroundView width=60的優先級就可以了 。
7, 關于抗拉伸優先級,沒想到很好的例子,就不演示了。
結語
一種布局效果能通過多種約束方式實現出來,關鍵是思路清晰,一步一步的來。
來自:http://www.jianshu.com/p/dff12ae004e9