最近看葉孤城的書爆哑,里面提到了UIStackView,說起這種布局舆吮,也是很早就知道了揭朝,但是一直沒有研究過,開發(fā)中也沒有使用過歪泳,周末上網(wǎng)翻看一下了大家的文章萝勤,發(fā)現(xiàn)大多都是Storyboard講解的露筒,實(shí)際上使用代碼或者Storyboard對于UIStackView區(qū)別不大呐伞,因?yàn)閁IStackView本身的屬性就很少,由于本人開發(fā)中從不使用Storyboard或者xib慎式, 本篇demo就用純代碼完成吧伶氢, 關(guān)鍵是網(wǎng)上的一些布局給的示例也不是特別清楚趟径,由于開發(fā)中也沒有實(shí)際用過,本文內(nèi)容僅限交流學(xué)習(xí)癣防, 大家交流指正蜗巧。
一,UIStackView是什么蕾盯?
在iOS9中蘋果在UIKit框架中引入了一個(gè)新的視圖類UIStackView幕屹。UIStackView 類提供了一個(gè)高效的接口用于平鋪一行或一列的視圖組合。Stack視圖管理著所有在它的 arrangedSubviews 屬性中的視圖的布局级遭。這些視圖根據(jù)它們在 arrangedSubviews 數(shù)組中的順序沿著 Stack 視圖的軸向排列望拖。
簡而言之,即UIStackView挫鸽,就是一個(gè)ContainerView说敏,可以沿橫向或縱向按照一定的規(guī)則布局內(nèi)部的子View。
為了避免太過無聊丢郊, 先放出demo中實(shí)現(xiàn)的一個(gè)效果盔沫, demo地址
二,一個(gè)快速示例
下面用一個(gè)很簡單的示例快速演示一下枫匾,
想一下要布局上圖中的View架诞,如果用Frame,或者autolayout的過程干茉,都是比較復(fù)雜侈贷,masonry中有一種相對簡單的方式, 可以看這篇文章masonry-等間距布局等脂,以上方式都不演示了俏蛮, 沒什么可說的。
如果使用UIStackView上遥, 如下為實(shí)現(xiàn)代碼:
- (void)viewDidLoad {
[super viewDidLoad];
containerView = [[UIStackView alloc] initWithFrame:CGRectMake(0, 100, ScreenWidth, 200)];
containerView.axis = UILayoutConstraintAxisHorizontal;
containerView.distribution = UIStackViewDistributionFillEqually;
containerView.spacing = 10;
containerView.alignment = UIStackViewAlignmentFill;
for (NSInteger i = 0; i < 4; i++) {
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor colorWithRed:random()%256/255.0 green:random()%256/255.0 blue:random()%256/255.0 alpha:1];
[containerView addArrangedSubview:view];
}
[self.view addSubview:containerView];
}
以上就是所有代碼搏屑, 是不是看起來異常簡單, 前面說過了StackView其實(shí)就是一個(gè)容器View粉楚,可以管理內(nèi)部子控件的布局辣恋, 那么看一下代碼, init不用說了模软, for循環(huán)創(chuàng)建子控件不用說了(addArrangedSubview:view
見下文)伟骨, addSubViews也不用說, 那么久只剩下了四行代碼燃异, 這四個(gè)也就是UIStackView全部四個(gè)屬性
[containerView addArrangedSubview:view]相關(guān)介紹:
UIStackView使用arrangedSubviews數(shù)組來管理子視圖携狭。
需要注意的是這個(gè)數(shù)組是一個(gè)readonly的屬性,我們需要調(diào)用方法對arrangedSubviews數(shù)組進(jìn)行操作回俐。
初始化數(shù)組:
- (instancetype)initWithArrangedSubviews:(NSArray<__kindof UIView *> *)views;
添加子視圖:
- (void)addArrangedSubview:(UIView *)view;
移除子視圖:
- (void)removeArrangedSubview:(UIView *)view;
根據(jù)下標(biāo)插入視圖:
- (void)insertArrangedSubview:(UIView *)view atIndex:(NSUInteger)stackIndex;
注意: addArrangedSubview 和 insertArrangedSubview逛腿, 會(huì)把子控件加到arrangedSubviews數(shù)組的同時(shí)添加到StackView上稀并,
但是removeArrangedSubview, 只會(huì)把子控件從arrangedSubviews數(shù)組中移除单默,
不會(huì)從subviews中移除碘举,如果需要可調(diào)用removeFromSuperview
三,具體講解StackView的屬性
1搁廓, axis:子控件的布局方向引颈,水平或垂直, 這個(gè)不用過多解釋了
2境蜕, spacing:子控件之間的最小間距线欲,之所以說是最小間距,因?yàn)閟tackView會(huì)根據(jù)一定的規(guī)則對內(nèi)部空間布局汽摹,有的時(shí)候不能滿足所有要求李丰,比如stackView 本身寬度100,內(nèi)部兩個(gè)控件逼泣,寬度都為50趴泌,50+50+10就超過了本身寬度, 這時(shí)會(huì)壓縮其中一個(gè)子控件的寬度來滿足最小間距拉庶。
3嗜憔, distribution:子控件依據(jù)何種規(guī)則布局, 這個(gè)比較抽象氏仗, 看示例理解的快一點(diǎn)吉捶,以下示例均使用UILabel演示, 原因見插播
插播:先了解一下什么是Intrinsic Content Size(固有尺寸)皆尔,
因?yàn)閁IStackView對子控件的布局是建立在Autolayout基礎(chǔ)之上的呐舔,
會(huì)涉及到Intrinsic Content Size
想一下當(dāng)為一個(gè)Label創(chuàng)建約束時(shí),是不是經(jīng)常只指定上邊距和左邊距慷蠕,
相信原因大家都知道珊拼,label內(nèi)部的文字自會(huì)撐開寬高,
這個(gè)根據(jù)內(nèi)容自己撐開的寬高就是Intrinsic Content Size流炕。
怎樣給一個(gè)UIView設(shè)置Intrinsic Content Size 或者改變label的Intrinsic Content Size澎现?
繼承然后重寫
- (CGSize)intrinsicContentSize
{
CGSize originalSize = [super intrinsicContentSize];
CGSize size = CGSizeMake(originalSize.width+20, originalSize.height+20);
return size;
}
UIStackViewDistribution
是個(gè)枚舉值每辟, 各個(gè)值如下剑辫, 配有示例圖, 看不懂就只能自求多福了:
UIStackViewDistributionFill
:它就是將 arrangedSubviews 填充滿整個(gè) StackView 渠欺,如果設(shè)置了spacing妹蔽,那么這些 arrangedSubviews 之間的間距就是spacing。如果減去所有的spacing,所有的 arrangedSubview 的固有尺寸( intrinsicContentSize )不能填滿或者超出 StackView 的尺寸讹开,那就會(huì)按照 Hugging 或者 CompressionResistance 的優(yōu)先級(jí)來拉伸或壓縮一些 arrangedSubview 盅视。如果出現(xiàn)優(yōu)先級(jí)相同的情況捐名,就按排列順序來拉伸或壓縮旦万。
UIStackViewDistributionFillEqually
:這種就是 StackView 的尺寸減去所有的spacing之后均分給 arrangedSubviews ,每個(gè) arrangedSubview 的尺寸是相同的镶蹋。
UIStackViewDistributionFillProportionally
:這種跟FillEqually差不多成艘,只不過這個(gè)不是講尺寸均分給 arrangedSubviews ,而是根據(jù) arrangedSubviews 的 intrinsicContentSize 按比例分配贺归。
UIStackViewDistributionEqualSpacing
:這種是使 arrangedSubview 之間的spacing相等淆两,但是這個(gè)spacing是有可能大于 StackView 所設(shè)置的spacing,但是絕對不會(huì)小于拂酣。這個(gè)類型的布局可以這樣理解秋冰,先按所有的 arrangedSubview 的 intrinsicContentSize 布局,然后余下的空間均分為spacing婶熬,如果大約 StackView 設(shè)置的spacing那這樣就OK了剑勾,如果小于就按照 StackView 設(shè)置的spacing,然后按照 CompressionResistance 的優(yōu)先級(jí)來壓縮一個(gè) arrangedSubview 赵颅。
UIStackViewDistributionEqualCentering
:這種是使 arrangedSubview 的中心點(diǎn)之間的距離相等虽另,這樣沒兩個(gè) arrangedSubview 之間的spacing就有可能不是相等的,但是這個(gè)spacing仍然是大于等于 StackView 設(shè)置的spacing的饺谬,不會(huì)是小于捂刺。這個(gè)類型布局仍然是如果 StackView 有多余的空間會(huì)均分給 arrangedSubviews 之間的spacing,如果空間不夠那就按照 CompressionResistance 的優(yōu)先級(jí)壓縮 arrangedSubview 募寨。
4族展,alignment 子控件對其方式,類似UIlabel的textAlignment拔鹰, 可以做一個(gè)類比苛谷, UILabel對應(yīng)UIStackView, label的內(nèi)容對應(yīng)StackView的子控件格郁。
UIStackViewDistribution
是個(gè)枚舉值腹殿, 各個(gè)值如下:
UIStackViewAlignmentFill
, 默認(rèn)方式, 如果子控件水平布局, 則指子控件的垂直方向填充滿stackView. 反之亦然
UIStackViewAlignmentLeading
, 如果子控件豎直布局, 則指子控件左邊對齊stackView左邊. 反之亦然, 即 UIStackViewAlignmentTop = UIStackViewAlignmentLeading例书。
UIStackViewAlignmentTop
= UIStackViewAlignmentLeading,
UIStackViewAlignmentFirstBaseline
, 根據(jù)上方基線布局所有子視圖的y值(適用于Horizontal模式)锣尉, 這種模式?jīng)]搞懂, 有知道怎么回事的求教了
UIStackViewAlignmentLastBaseline
, 根據(jù)下方基線布局所有子視圖的y值(適用于Horizontal模式)
UIStackViewAlignmentCenter
, 中心對齊
UIStackViewAlignmentTrailing
, 如果子控件豎直布局, 則指子控件左邊對齊stackView右邊. 反之亦然, 即UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing
UIStackViewAlignmentBottom
= UIStackViewAlignmentTrailing,
四决采, 另一個(gè)有意思一點(diǎn)的示例自沧, 同時(shí)演示stackView的嵌套
即文章開頭放出的動(dòng)態(tài)圖,
這個(gè)效果使用了兩個(gè)StackView, 一個(gè)horizontalView拇厢, 一個(gè)verticalView爱谁,horizontalView即示例下方水平排布的View, 這個(gè)horizontalView也添加到verticalView的arrangedSubviews數(shù)組中孝偎, 具體實(shí)現(xiàn)看代碼吧访敌, 不多說了
github地址 : UIStackVIewDemo