UIStackView
UIStackView介紹
隨著autolayout的推廣開(kāi)來(lái),更多的app開(kāi)始使用自動(dòng)布局的方式來(lái)構(gòu)建自己的UI系統(tǒng),autolayout配合storyBoard和一些第三方的框架,對(duì)于創(chuàng)建約束來(lái)說(shuō),已經(jīng)十分方便,但是對(duì)于一些動(dòng)態(tài)的線(xiàn)性布局的視圖,我們需要手動(dòng)添加的約束不僅非常多,而且如果我們需要插入或者移除其中的一些UI元素的時(shí)候,我們又要做大量的修改約束的工作,UIStackView正好可以解決這樣的問(wèn)題。
UIStackView 是 iOS 9 中新增的一個(gè)控件,它繼承于UIView,用來(lái)管理一行或一列視圖的布局(堆疊視圖的控制器類(lèi)視圖,所謂堆疊視圖時(shí)一種平鋪式的線(xiàn)性布局方式,不可重疊,布局方向也不可交錯(cuò))。UIStackView新增了幾個(gè)屬性,這些屬性就是子視圖布局規(guī)則。一旦UIStackView的這些屬性發(fā)生變化,它的arrangedSubviews就會(huì)按照規(guī)則重新排布。只要我們掌握這些規(guī)則,就可以管理視圖布局了。如果能再稍加靈活運(yùn)用,有時(shí)候我們甚至能輕松實(shí)現(xiàn)一些精妙布局。 UIStackView可以幫助開(kāi)發(fā)者更加簡(jiǎn)單的使用layout而不必手動(dòng)添加太多布局約束.
| 屬 性 | 作 用 |
|---|---|
| Axis | 屬性決定了 stack 的朝向,只有垂直或水平 |
| distribution | 屬性決定了其管理的視圖在沿著其軸向上的布局 |
| Alignment | 屬性決定了其管理的視圖在垂直于其軸向上的布局 |
| Spacing | 屬性決定了其管理的視圖間的最小間隙 |
| layoutMarginsRelativeArrangement | 屬性決定了 stack 視圖平鋪其管理的視圖時(shí)是否要參照它的布局邊距 |
| baselineRelativeArrangement | 屬性決定了 stack 視圖平鋪其管理的視圖時(shí)是否要參照它的布局邊距 |
![Uploading 19_081418.png . . .]
](http://upload-images.jianshu.io/upload_images/1129706-a300c78a3ddc0cdb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
UIStackViewDistribution
axis、spacing、distribution和alignment是比較重要的4個(gè)屬性,他們都能給布局帶來(lái)明顯的變化。axis和spacing屬性作用單一,通過(guò)屬性解釋或者通過(guò)視圖簡(jiǎn)單觀(guān)察我們就能理解他們的作用。distribution和alignment這兩個(gè)屬性相對(duì)而言更具靈活性,也更具有難度,尤其是二者的結(jié)合使用。
public enum UIStackViewDistribution : Int {
case fill
case fillEqually
case fillProportionally
case equalSpacing
case equalCentering
}
public enum UIStackViewAlignment : Int {
case fill
case leading
public static var top: UIStackViewAlignment { get }
case firstBaseline
case center
case trailing
public static var bottom: UIStackViewAlignment { get }
case lastBaseline
}
UIStackViewDistributionFill
將arrangedSubviews填充滿(mǎn)整個(gè)StackView,他們之間的間隙等于spacing大小
如果減去所有的spacing,所有arrangedSubview的固有尺寸(intrinsicContentSize)之和不能填滿(mǎn)StackView,那么就按照Hugging的優(yōu)先級(jí)將其拉伸。反之,如果超出StackView的尺寸則按CompressionResistance的優(yōu)先級(jí)壓縮。如果優(yōu)先級(jí)相同,就按排列順序來(lái)拉伸或壓縮。


UIStackViewDistributionFillEqually
每個(gè)arrangedSubview沿axis方向的長(zhǎng)度相等,等于StackView沿axis長(zhǎng)度減去spacing之和除以arrangedSubviews個(gè)數(shù)。

-
UIStackViewDistributionFillProportionally根據(jù)arrangedSubview的intrinsicContentSize,將StackView沿axis方向的長(zhǎng)度減去spacing之和按比例分配給arrangedSubviews。

-
UIStackViewDistributionEqualSpacing先按arrangedSubviews的intrinsicContentSize布局,然后余下的空間均分為spacing
如果spacing小于StackView設(shè)置的spacing,則按照CompressionResistance的優(yōu)先級(jí)來(lái)壓縮arrangedSubviews。

-
UIStackViewDistributionEqualCentering令arrangedSubviews的中心點(diǎn)之間的距離相等,且spacing大于等于StackView設(shè)置的spacing(每?jī)蓚€(gè)arrangedSubview之間的spacing可能不相等)
如果spacing小于StackView設(shè)置的spacing,則按照CompressionResistance的優(yōu)先級(jí)來(lái)壓縮arrangedSubviews。

UIStackViewalignment
-
UIStackViewAlignmentFill在StackView軸向的垂直方向上拉伸所有子view來(lái)填充StackView

-
UIStackViewAlignmentLeading用于stackview是垂直軸向時(shí),所有子view靠左對(duì)齊

-
UIStackViewAlignmentTop用于stackview是水平軸向時(shí),所有子view靠頂部對(duì)齊

-
UIStackViewAlignmentCenter在StackView軸向的垂直方向上子視圖以中線(xiàn)為基準(zhǔn)對(duì)齊

-
UIStackViewAlignmentTrailing用于stackview是垂直軸向時(shí),所有子view靠右對(duì)齊

-
UIStackViewAlignmentBottom用于stackview是水平軸向時(shí),所有子view靠底部對(duì)齊

-
UIStackViewAlignmentFirstBaseline用于stackview是水平軸向時(shí),按照第一個(gè)子視圖中文字的第一行對(duì)齊

-
UIStackViewAlignmentLastBaseline用于stackview是水平軸向時(shí),按照最后一個(gè)子視圖中文字的最后一行對(duì)齊

storyboard添加StackView
- IB
從對(duì)象庫(kù)中拖拽UIStackView到storyboard中,然后往內(nèi)部扔控件(UIView或其子類(lèi))就可以了。選擇storyboard中的控件,可以用“command鍵 + 單擊”進(jìn)行多選,然后點(diǎn)擊下方的stack按鈕,這樣選中的控件就會(huì)被放入一個(gè)StackView中。

代碼添加StackView
- 創(chuàng)建
UIStackView
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[forkingLabel, logoImageView, dogLabel]];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.distribution = UIStackViewDistributionFill;
stackView.alignment = UIStackViewAlignmentCenter;
stackView.spacing = 0;
[self.view addSubview:stackView];
- 動(dòng)態(tài)的改變其中view的個(gè)數(shù)
UIView * newView = [[UIView alloc]init];
[stackView addArrangedSubview:newView];
特別注意:addArrangedSubview和addSubview有很大的區(qū)別,使用前者是將視圖添加進(jìn)StackView的布局管理,后者只是簡(jiǎn)單的加在視圖的層級(jí)上,并不接受StackView的布局管理。
- 與之相對(duì),我們可以使用下面的方法移除一個(gè)view
UIView * view = [stackView arrangedSubviews].lastObject;
[stackView removeArrangedSubview:view];
StackView使用技巧
- 嵌套 只要嵌套好UIStackView,就可以用很少的約束達(dá)到自動(dòng)布局界面的目的
使用StackView 嵌套 模仿同程首頁(yè)布局


- 結(jié)合sizeClass 多屏幕適配
查看SatckView的Attributes Inspector,我們會(huì)發(fā)現(xiàn)StackView的幾個(gè)主要屬性都是可以設(shè)置sizeclass模式的,
這對(duì)我們的屏幕適配將會(huì)大有助益。再加上約束的sizeClass,靈活性可以想象。

- 因?yàn)?code>StackView繼承于
UIView,因此在布局改變的時(shí)候,我們可以使用UIView層的動(dòng)畫(huà) 添加view的時(shí)候會(huì)有動(dòng)畫(huà)效果,移除的時(shí)候沒(méi)有
[stackView addArrangedSubview:newView];
[UIView animateWithDuration:1 animations:^{
[stackView layoutIfNeeded];
}];

FDStackView
UIStackView是在iOS9才推出的,最低支持的系統(tǒng)也是iOS9, FDStackView出現(xiàn)了,它就是為了解決UIStackView在低于iOS9的系統(tǒng)下無(wú)法使用的問(wèn)題
在FDStackView之前也已經(jīng)有了一些類(lèi)似的開(kāi)源項(xiàng)目,比如OAStackView和TZStackView,然而他們都不能滿(mǎn)足我們的需求,局限性還是比較大的,比如不支持IB,某些功能還沒(méi)有實(shí)現(xiàn),類(lèi)名需要使用非UIStackView,在我們看來(lái)這些對(duì)開(kāi)發(fā)者來(lái)說(shuō)都是不友好的,開(kāi)發(fā)者需要的是一款功能完善,支持IB,使用時(shí)完全無(wú)感,在Xcode7上直接使用UIStackView即可,接下來(lái)的事情交給FDStackView就好,它負(fù)責(zé)將UIStackView在低于iOS9的系統(tǒng)上運(yùn)行。
需要注意如果使用IB的話(huà),那么IB的Builds for屬性需要設(shè)置為iOS 9.0 and later

-
forkingdog開(kāi)源小組的成員實(shí)現(xiàn)原理介紹
- FDStackView —— Downward Compatible UIStackView (Part 1)
- FDStackView —— Downward Compatible UIStackView (Part 2)
- FDStackView —— Downward Compatible UIStackView (Part 3)
