可以維護(hù)的 AutoLayout
在使用 AutoLayout
做界面布局的時(shí)候芯丧,你會(huì)發(fā)現(xiàn)芍阎,做好一個(gè)復(fù)雜界面的約束并不是一件容易的事,經(jīng)常需要很多的調(diào)試缨恒,這在用代碼寫布局的時(shí)候尤為明顯谴咸,因?yàn)闆](méi)有 IB 給你實(shí)時(shí)的反饋當(dāng)前的 Layout 錯(cuò)誤。而且不管是在 IB 還是純代碼的 AutoLayout
骗露,其可讀性都不太好岭佳,例如我們創(chuàng)建了下面這樣一個(gè) App Store 的界面:
Label
和 星標(biāo)圖片之間有很多約束,如果我們遇到了需求改動(dòng)萧锉,想要在星標(biāo)上方多加一行珊随,就得先搞清楚各個(gè)約束是干什么的,再打破幾個(gè)約束柿隙,最后增加一個(gè) Label
并且加上約束叶洞,費(fèi)時(shí)費(fèi)力。
iOS 9 發(fā)布的時(shí)候蘋果提供了一個(gè)新的AutoLayout
工具 UIStackView
优俘,可以自動(dòng)完成很多類型的布局京办,并且不用添加任何約束,由 UIStackView
自行管理其 ArrangedSubviews
的約束并且可以讓增刪變的更簡(jiǎn)單帆焕,大大增加了項(xiàng)目的可維護(hù)性惭婿,本文就來(lái)介紹一下 UIStackView
的使用。
UIStackView
本身是建立在 AutoLayout
的約束之上的叶雹,我們不用主動(dòng)給其子視圖添加約束就可以完成自動(dòng)布局财饥,UIStackView
相當(dāng)于一個(gè)可以為你自動(dòng)管理內(nèi)部 View 的一個(gè)容器。想要完成布局大多數(shù)情況你需要做這三步:
1.調(diào)用 -addArrangedSubview: 添加需要布局的 View 到一個(gè) UIStackView 上折晦;
2.配置 UIStackView 的 axix钥星、alignment、distribution满着、spaciing 這四個(gè)屬性谦炒;
3.如果有必要,再嵌套多個(gè) UIStackView 到一個(gè) UIStackView 中风喇。
UIStackView 的主要方法和屬性
@property(nonatomic) UILayoutConstraintAxis axis;
用于控制 UIStackView
子視圖橫向或縱向布局宁改,有兩種:
-
UILayoutConstraintAxisHorizontal
橫向布局 -
UILayoutConstraintAxisVertical
縱向布局
@property(nonatomic) UIStackViewAlignment alignment;
這個(gè)屬性稍微復(fù)雜一點(diǎn),當(dāng) axis
是 Horizontal
時(shí)其表示 UIStackView
的子視圖相對(duì)于其上下邊界的對(duì)其方式魂莫。當(dāng) axis 為 Vertical 時(shí)还蹲,表示 UIStackView 的子視圖相對(duì)于其左右邊界的對(duì)其方式,一共有八中,看下面的圖示就很好理解了:
@property(nonatomic) UIStackViewDistribution distribution;
這個(gè)屬性用來(lái)控制 UIStackView
在其 axis
方向上的分布谜喊,分別有如下幾種:
Fill
UIStackView
的子視圖會(huì)沿著其 axis
填充滿 UIStackView
潭兽,如果子視圖在 axis
方向上不能放入 StackView
(StackView
太小)斗遏,則會(huì)按照子視圖的抗壓縮優(yōu)先級(jí)屬性( Content Compression Resistance Priority)從低到高壓縮視圖山卦,直到正好填滿 StackView
為止。
反之最易,如果子視圖在 axis
方向不能填滿 StackView
(StackView
太大)怒坯,則會(huì)按照子視圖的抗拉伸優(yōu)先級(jí)屬性(Content Hugging Priority)從低到高拉伸視圖,知道正好填滿 StackView 為止藻懒。
這里說(shuō)一點(diǎn),StackView
在沒(méi)有寬高約束的時(shí)候大部分情況是沒(méi)問(wèn)題的视译,因?yàn)樗鼤?huì)根據(jù)子視圖的intrinsic content size
嬉荆、寬高約束、甚至是 frame.size.width
frame.size.height
來(lái)計(jì)算自己的寬高酷含,最終會(huì)有一個(gè)intrinsic content size
鄙早,這樣我們把 StackView 添加到父視圖中的時(shí)候,可以不約束其寬高椅亚,只定位好 origin
就可以了限番。
FillEqually
這個(gè)屬性簡(jiǎn)單一些,StackView
的子視圖會(huì)沿著axis
在 StackView
內(nèi)均勻分布呀舔。
FillProportionally
按字面意思解釋弥虐,和 FillEqually
類似,也是每個(gè)子視圖都會(huì)被等比例拉伸或者壓縮媚赖,來(lái)填滿 StackView
霜瘪,但是這個(gè)是等比例填滿,每個(gè)子視圖會(huì)被 StackView
按照其 intrinsic content size
或者其本身 frame
來(lái)進(jìn)行等比例縮放惧磺,如果要拉伸或者壓縮颖对,每個(gè)子視圖都會(huì)同時(shí)被等比例拉伸或壓縮。
EqualSpacing
StackView
會(huì)在每個(gè)子視圖中間留下等相等的空間距磨隘,此時(shí) Spacing
屬性定義的是這個(gè)間距的最小值缤底。如果 StackView
足夠大,可以保持子視圖的原始尺寸番捂,不拉伸个唧,但是如果 StackView 太小
,子視圖會(huì)被壓縮白嘁,也是按照子視圖的抗壓縮優(yōu)先級(jí)屬性( Content Compression Resistance Priority)從低到高壓縮坑鱼,此時(shí)如果有兩個(gè)子視圖有相等的抗壓縮優(yōu)先級(jí),StackView
就不知道壓縮哪個(gè)了,需要調(diào)整子視圖的優(yōu)先級(jí)鲁沥,不要出現(xiàn)相等的情況呼股。
EqualCentering
StackView
會(huì)把每個(gè)子視圖按照中心點(diǎn)等距離排列,此時(shí) Spacing
屬性定義的是這個(gè)間距的最小值画恰。如果 StackView
足夠大彭谁,可以保持子視圖的原始尺寸,不拉伸允扇,但是如果 StackView
太小缠局,子視圖會(huì)被壓縮,也是按照子視圖的抗壓縮優(yōu)先級(jí)屬性( Content Compression Resistance Priority)從低到高壓縮考润,此時(shí)如果有兩個(gè)子視圖有相等的抗壓縮優(yōu)先級(jí)狭园,StackView
就不知道壓縮哪個(gè)了,需要調(diào)整子視圖的優(yōu)先級(jí)糊治,不要出現(xiàn)相等的情況唱矛。
@property(nonatomic) UIStackViewAlignment alignment;
按照 distribution
屬性中的布局方式控制子視圖之間的間距。
總結(jié)
在本文結(jié)束之前井辜,我們看一下上面的 AppStore Demo 在使用 UIStackView 布局后的情況绎谦,是不是簡(jiǎn)介清爽了許多。
最后粥脚,引用一下 WWDC 蘋果工程師的話窃肠,如果你使用 AutoLayout,那么請(qǐng) Start With Stack View, use constraints as needed!