這是關于自動布局的第二篇文章薄扁。
<< Auto Layout的使用
上一篇文章介紹了如何使用Auto Layout率寡,這一篇文章主要介紹堆棧視圖(Stack View)迫卢。Stack View提供了一種輕松的方式來使用Auto Layout,不需要引入復雜的約束冶共。單個堆棧視圖定義用戶界面的行或列,堆棧視圖根據(jù)以下屬性來排列其子視圖每界。
-
axis:定義Stack View的方向捅僵,水平方向或豎直方向,只適用于
UIStackView
眨层。NSStackView
中定義方向使用orientation
屬性庙楚。 - distribution:設定視圖沿軸線的排布方式。
- alignment:設定如何沿軸線垂直方向排布子視圖趴樱。
- spacing:設定子視圖間距馒闷。
UIStackView
適用于iOS 9.0+和tvOS 9.0+,NSStackView
適用于macOS 10.9+叁征。這篇文章只講解UIStackView
纳账。
使用Stack View時可以先從對象庫中拖拽出Horizontal Stack View或Vertical Stack View到storyboard,后把需要添加的視圖放進Stack View捺疼;也可以先添加視圖疏虫,后點擊Auto Layout工具Embed in Stack,Auto Layout會根據(jù)視圖布局插入水平或垂直堆棧視圖,也可以點擊Editor > Embed In > Stack View插入堆棧視圖卧秘,與點擊Embed In Stack插入沒有區(qū)別呢袱。
1. 創(chuàng)建demo
這里使用Tabbed Application的模板創(chuàng)建demo,Product Name為StackView翅敌,選擇文件位置羞福,創(chuàng)建工程。
下面通過三個示例來學習Stack View蚯涮。
2. 示例1
打開剛創(chuàng)建demo的Main.storyboard坯临,在First Scene添加以下視圖:第一行為UILabel
和UISwitch
,第二行為兩個UIImageView
恋昼。
選中第一行的UILabel
和UISwitch
看靠,點擊Embed In Stack插入Stack View。打開Attributes Inspector液肌,設置Stack View的屬性如下:
- Axis:Horizontal挟炬,自動創(chuàng)建的應該為Horizontal,不需要修改嗦哆。
- Alignment:Center
- Distribution:Fill谤祖,不需要修改。
- Spacing:
16
選中兩個UIImageView
老速,重復上面插入Stack View步驟并修改屬性粥喜,屬性與上面相同。UIImageView
中圖片的Content Mode屬性為Aspect Fit橘券。
選中剛添加的兩個Stack View额湘,點擊Embed In Stack再次插入一個堆棧視圖。堆棧視圖可以嵌入堆棧視圖旁舰。界面構(gòu)建器會自動插入一個垂直堆棧視圖锋华。修改其屬性如下:
- Axis:Vertical,不需要修改箭窜。
- Alignment:Center
- Distribution:Fill毯焕,不需要修改。
- Spacing:
16
堆棧視圖根據(jù)子視圖大小來調(diào)整自身大小磺樱,這里子視圖保持固有內(nèi)容大小纳猫,所以只需要添加約束指定堆棧視圖位置,不需要約束堆棧視圖大小竹捉。
添加約束指定堆棧視圖水平居中芜辕,與Top距離為20
points。如果添加過程遇到問題活孩,你可以點擊這里查看demo物遇,也可以查看上一篇文章學習如何添加約束乖仇。添加完畢后視圖層級如下:
使用Stack View時一般只需要指定堆棧視圖位置,堆棧視圖大小會根據(jù)子視圖大小動態(tài)調(diào)整询兴。
堆棧視圖中子視圖顯示順序由其在
arrangedSubviews
數(shù)組的順序決定乃沙。在水平堆棧視圖中,視圖顯示方向與閱讀方向一致诗舰,arrangedSubviews
數(shù)組中低索引號視圖先顯示警儒。在垂直堆棧視圖中,視圖從上向下顯示眶根,低索引號視圖在上蜀铲,高索引號視圖在下。
當向arrangedSubviews
數(shù)組中添加属百、移除視圖時记劝,或視圖被隱藏時,Stack View會自動調(diào)整布局族扰。
下面從UISwitch
連接出一個IBAction的屬性厌丑,當點擊UISwitch
時,調(diào)整imageStackView
的axis
渔呵。imageStackView
為storyboard中圖片堆棧視圖的IBOutlet屬性怒竿。
- (IBAction)axisChange:(UISwitch *)sender
{
[UIView animateWithDuration:0.25 animations:^{
[self updateConstraintsForAxis];
}];
}
- (void)updateConstraintsForAxis
{
// 在水平、垂直堆棧視圖間切換
if (self.imageStackView.axis == UILayoutConstraintAxisHorizontal)
{
self.imageStackView.axis = UILayoutConstraintAxisVertical;
}
else
{
self.imageStackView.axis = UILayoutConstraintAxisHorizontal;
}
}
使用animateWithDuration: animations:
方法可以讓視圖的變換以動畫形式呈現(xiàn)扩氢。
3. 示例2
通過示例1
我們可以在runtime手動修改堆棧視圖axis
耕驰,但更好的方式是Stack View自動跟隨設備旋轉(zhuǎn)。例如录豺,當設備從豎屏(portrait)旋轉(zhuǎn)為橫屏(landscape)時朦肘,堆棧視圖axis
屬性自動從UILayoutConstraintAxisVertical
調(diào)整為UILayoutConstraintAxisHorizontal
。
進入Second Scene巩检,添加兩個UIImageView
厚骗,其contentMode
屬性為Aspect Fit,圖片分別為Heart兢哭、Star,可以通過文章底部網(wǎng)址下載源碼獲取圖片夫嗓。選中兩個UIImageView
插入一個Horizontal堆棧視圖迟螺。堆棧視圖與Leading、Trailing舍咖、Top矩父、Bottom距離分別為0
、0
排霉、Standard Value
窍株、Standard Value
。Stack View其它屬性如下:
- Axis:Horizontal
- Alignment:Center
- Distribution:Fill Proportionally
- Spacing:
0
上面的Distribution有Fill、Fill Equally球订、Fill Proportionally后裸、Equal Spacing、Equal Centering五個屬性冒滩,這五個屬性的區(qū)別:
-
UIStackViewDistributionFill:Stack View調(diào)整子視圖大小以便填充所有可用空間微驶。當子視圖大小大于可用空間時,根據(jù)Compression Resistance優(yōu)先級壓縮視圖开睡;當子視圖不能填充滿可用空間時因苹,根據(jù)Content Hugging優(yōu)先級拉伸視圖。如果優(yōu)先級相同篇恒,優(yōu)先調(diào)整
arrangedSubviews
數(shù)組中index小的視圖扶檐。 - UIStackViewDistributionFillEqually:調(diào)整所有子視圖為相同大小,占用所有可用空間胁艰。
-
UIStackViewDistributionFillProportionally:會保持每一個子視圖的固有大小款筑,但如果有可用空間、或需要壓縮視圖蝗茁,會按比例拉伸醋虏、壓縮。如一個視圖寬為
100
哮翘,另一個視圖寬為200
颈嚼,Stack View想要拉伸視圖以便填充可用空間,第一個視圖寬被拉伸為150
饭寺,第二個視圖寬就會被拉伸為300
阻课。 -
UIStackViewDistributionEqualSpacing:不調(diào)整子視圖大小,通過移動子視圖位置讓子視圖間距相等艰匙。如果子視圖大于可用空間限煞,會按照Compression Resistance優(yōu)先級壓縮。如果優(yōu)先級相同员凝,優(yōu)先調(diào)整
arrangedSubviews
數(shù)組中index小的視圖署驻。 -
UIStackViewDistributionEqualCentering:讓子視圖的中心距離相等。如果視圖大于可用空間健霹,會壓縮spacing屬性直到設定的最小值旺上,如果此時仍舊大于可用空間,會根據(jù)子視圖Compression Resistance優(yōu)先級壓縮子視圖糖埋。如果優(yōu)先級相同宣吱,優(yōu)先調(diào)整
arrangedSubviews
數(shù)組中index小的視圖。
選中Stack View瞳别,打開Attributes Inspector征候,你會發(fā)現(xiàn)每一個Stack View屬性前會有一個+
杭攻。
點擊這些+
,可以自定義水平疤坝、垂直堆棧視圖的屬性兆解。下面添加一個當寬度為compact、高度為regular時axis
為垂直的屬性卒煞。
你還可以通過相同方式痪宰,添加一個當寬度為compact、高度為regular時spacing
屬性畔裕,一般不需要添加其它屬性衣撬。
現(xiàn)在運行app,當豎屏時扮饶,堆棧視圖的axis是垂直的具练;當橫屏時,堆棧視圖的axis是水平的甜无。
4. 示例3
Stack View主要優(yōu)點之一是會自動為其每個子視圖創(chuàng)建自動布局約束扛点,也可以對這些子視圖的大小和位置進行設置。
為剛創(chuàng)建的demo添加一個View Controller岂丘,并連接到選項卡控制器陵究,設定Bar Item的標題為Third
。
打開Third Scene奥帘,自上而下添加UILabel
铜邮、UIImageView
、UIButton
寨蹋,并插入到一個垂直堆棧視圖中松蒜。堆棧視圖屬性設置如下:
- Axis: Vertical
- Alignment: Center
- Distribution: Equal Spacing
- Spacing:
0
其中UIImageView
的contentMode
為Aspect Fit,為上面Stack View添加約束已旧,與Leading秸苗、Trailing、Top距離分別為0
运褪、0
惊楼、20
。
在上圖Add Star下面添加一個水平堆棧視圖秸讹,屬性設置如下:
- Axis: Horizontal
- Alignment: Center
- Distribution: Fill Equally
- Spacing:
10
完成后為其添加約束胁后,與Leading、Trailing嗦枢、Top、Bottom距離分別為0
屯断、0
文虏、Standard Value
侣诺、20
,高度為120
氧秘。
雖然UIStackView
繼承自UIView
年鸳,但它只管理子視圖的位置和大小,不提供用戶界面丸相,也就是有些屬性不適用于UIStackView
搔确,如backgroundColor
,也不能重寫drawRect:
方法灭忠。
堆棧視圖中有subviews
和arrangedSubviews
兩個屬性膳算,其遵守以下規(guī)則。
- 當Stack View向
arrangedSubviews
數(shù)組添加視圖時弛作,也會將該視圖添加為subviews
涕蜂。 - 從Stack View移除一個視圖,該視圖也會被從
arrangedSubviews
數(shù)組移除映琳。 - 從
arrangedSubviews
數(shù)組移除一個視圖机隙,該視圖依然存在于subviews
數(shù)組。Stack View不在管理被移除視圖的位置和大小萨西,但它會存在于視圖層級中有鹿。
所以,通過調(diào)用addArrangedSubview:
或insertArrangedSubview: atIndex:
方法向arrangedSubviews
數(shù)組添加元素谎脯,該元素同時會被加入subviews
數(shù)組葱跋。通過removeFromSuperView
方法移除的視圖,會被同步從arrangedSubviews
數(shù)組移除穿肄。通過removeArrangedSubview:
移除的視圖年局,還會存在于subviews
數(shù)組。
從UIButton
連接出一個名為addStar
的IBAction點擊事件咸产。當點擊時矢否,在底部的horizontalStackView
添加一個五角星。
- (IBAction)addStar:(UIButton *)sender
{
UIImageView *filledStarView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"filledStar"]];
// 添加視圖到堆棧視圖
[self.horizontalStackView addArrangedSubview:filledStarView];
filledStarView.contentMode = UIViewContentModeScaleAspectFit;
[UIView animateWithDuration:0.25 animations:^{
[self.horizontalStackView layoutIfNeeded];
}];
}
現(xiàn)在增加移除五角星的功能脑溢。從對象庫拖拽一個UIButton
到Add Star下方僵朗。選中UIButton
和Add Star,點擊Embed In Stack按鈕插入堆棧視圖屑彻。修改剛插入堆棧視圖屬性如下:
- Axis: Horizontal
- Alignment: Center
- Distribution: Equal Spacing
- Spacing:
10
剛添加UIButton
標題為Remove Star
验庙,文字顏色為red
。
為剛添加的UIButton
創(chuàng)建名為removeStar
的IBAction點擊事件社牲,并實現(xiàn)移除方法粪薛。
- (IBAction)removeStar:(UIButton *)sender
{
UIView *filledView = self.horizontalStackView.arrangedSubviews.lastObject;
// 如果視圖存在,移除視圖
if (filledView)
{
[filledView removeFromSuperview]; // 會自動從arrangedSubviews移除
[UIView animateWithDuration:0.25 animations:^{
[self.horizontalStackView layoutIfNeeded];
}];
}
}
運行app搏恤,現(xiàn)在可以添加违寿、移除五角星湃交,且視圖會隨著設備旋轉(zhuǎn)自動調(diào)整布局。
總結(jié)
通過這篇文章藤巢,可以看到UIStackView
極大降低了用戶界面開發(fā)難度搞莺,簡化了許多工作,僅僅添加少量約束便可實現(xiàn)自動布局掂咒。在布局時才沧,應該優(yōu)先考慮使用Stack View來布局界面。
Demo名稱:StackView
源碼地址:https://github.com/pro648/BasicDemos-iOS
參考資料: