iOS AutoLayout還可以這樣玩

hejunm發表於2017-12-26

Auto Layout


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


demo效果

demo效果

demo 中要通過約束要實現的效果如下:

  1. backgroundView width>=60;
  2. backgroundView的width隨著Label中內容的增加而增加
  3. 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 prioritiescompression-resistance priorities用於抵抗其他約束對viewIntrinsic 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, 關於抗拉伸優先順序,沒想到很好的例子,就不演示了。

結語

一種佈局效果能通過多種約束方式實現出來,關鍵是思路清晰,一步一步的來。 參考資料,當然是 官網了。希望對你有幫助,如有幫助就給個喜歡吧。

相關文章