可以維護的 AutoLayout
在使用 AutoLayout
做界面布局的時候,你會發現,做好一個復雜界面的約束并不是一件容易的事,經常需要很多的調試,這在用代碼寫布局的時候尤為明顯,因為沒有 IB 給你實時的反饋當前的 Layout 錯誤。而且不管是在 IB 還是純代碼的 AutoLayout
,其可讀性都不太好,例如我們創建了下面這樣一個 App Store 的界面:
Label
和 星標圖片之間有很多約束,如果我們遇到了需求改動,想要在星標上方多加一行,就得先搞清楚各個約束是干什么的,再打破幾個約束,最后增加一個 Label
并且加上約束,費時費力。
iOS 9 發布的時候蘋果提供了一個新的AutoLayout
工具 UIStackView
,可以自動完成很多類型的布局,并且不用添加任何約束,由 UIStackView
自行管理其 ArrangedSubviews
的約束并且可以讓增刪變的更簡單,大大增加了項目的可維護性,本文就來介紹一下 UIStackView
的使用。
UIStackView
本身是建立在 AutoLayout
的約束之上的,我們不用主動給其子視圖添加約束就可以完成自動布局,UIStackView
相當于一個可以為你自動管理內部 View 的一個容器。想要完成布局大多數情況你需要做這三步:
1.調用 -addArrangedSubview: 添加需要布局的 View 到一個 UIStackView 上;
2.配置 UIStackView 的 axix、alignment、distribution、spaciing 這四個屬性;
3.如果有必要,再嵌套多個 UIStackView 到一個 UIStackView 中。
UIStackView 的主要方法和屬性
@property(nonatomic) UILayoutConstraintAxis axis;
用于控制 UIStackView
子視圖橫向或縱向布局,有兩種:
-
UILayoutConstraintAxisHorizontal
橫向布局 -
UILayoutConstraintAxisVertical
縱向布局
@property(nonatomic) UIStackViewAlignment alignment;
這個屬性稍微復雜一點,當 axis
是 Horizontal
時其表示 UIStackView
的子視圖相對于其上下邊界的對其方式。當 axis 為 Vertical 時,表示 UIStackView 的子視圖相對于其左右邊界的對其方式,一共有八中,看下面的圖示就很好理解了:
@property(nonatomic) UIStackViewDistribution distribution;
這個屬性用來控制 UIStackView
在其 axis
方向上的分布,分別有如下幾種:
Fill
UIStackView
的子視圖會沿著其 axis
填充滿 UIStackView
,如果子視圖在 axis
方向上不能放入 StackView
(StackView
太小),則會按照子視圖的抗壓縮優先級屬性( Content Compression Resistance Priority)從低到高壓縮視圖,直到正好填滿 StackView
為止。
反之,如果子視圖在 axis
方向不能填滿 StackView
(StackView
太大),則會按照子視圖的抗拉伸優先級屬性(Content Hugging Priority)從低到高拉伸視圖,知道正好填滿 StackView 為止。
這里說一點,StackView
在沒有寬高約束的時候大部分情況是沒問題的,因為它會根據子視圖的intrinsic content size
、寬高約束、甚至是 frame.size.width
frame.size.height
來計算自己的寬高,最終會有一個intrinsic content size
,這樣我們把 StackView 添加到父視圖中的時候,可以不約束其寬高,只定位好 origin
就可以了。
FillEqually
這個屬性簡單一些,StackView
的子視圖會沿著axis
在 StackView
內均勻分布。
FillProportionally
按字面意思解釋,和 FillEqually
類似,也是每個子視圖都會被等比例拉伸或者壓縮,來填滿 StackView
,但是這個是等比例填滿,每個子視圖會被 StackView
按照其 intrinsic content size
或者其本身 frame
來進行等比例縮放,如果要拉伸或者壓縮,每個子視圖都會同時被等比例拉伸或壓縮。
EqualSpacing
StackView
會在每個子視圖中間留下等相等的空間距,此時 Spacing
屬性定義的是這個間距的最小值。如果 StackView
足夠大,可以保持子視圖的原始尺寸,不拉伸,但是如果 StackView 太小
,子視圖會被壓縮,也是按照子視圖的抗壓縮優先級屬性( Content Compression Resistance Priority)從低到高壓縮,此時如果有兩個子視圖有相等的抗壓縮優先級,StackView
就不知道壓縮哪個了,需要調整子視圖的優先級,不要出現相等的情況。
EqualCentering
StackView
會把每個子視圖按照中心點等距離排列,此時 Spacing
屬性定義的是這個間距的最小值。如果 StackView
足夠大,可以保持子視圖的原始尺寸,不拉伸,但是如果 StackView
太小,子視圖會被壓縮,也是按照子視圖的抗壓縮優先級屬性( Content Compression Resistance Priority)從低到高壓縮,此時如果有兩個子視圖有相等的抗壓縮優先級,StackView
就不知道壓縮哪個了,需要調整子視圖的優先級,不要出現相等的情況。
@property(nonatomic) UIStackViewAlignment alignment;
按照 distribution
屬性中的布局方式控制子視圖之間的間距。
總結
在本文結束之前,我們看一下上面的 AppStore Demo 在使用 UIStackView 布局后的情況,是不是簡介清爽了許多。
最后,引用一下 WWDC 蘋果工程師的話,如果你使用 AutoLayout,那么請 Start With Stack View, use constraints as needed!