Auto Layout中Stack View的使用

這是關于自動布局的第二篇文章薄扁。
<< Auto Layout的使用

上一篇文章介紹了如何使用Auto Layout率寡,這一篇文章主要介紹堆棧視圖(Stack View)迫卢。Stack View提供了一種輕松的方式來使用Auto Layout,不需要引入復雜的約束冶共。單個堆棧視圖定義用戶界面的行或列,堆棧視圖根據(jù)以下屬性來排列其子視圖每界。

  • axis:定義Stack View的方向捅僵,水平方向或豎直方向,只適用于UIStackView眨层。NSStackView中定義方向使用orientation屬性庙楚。
  • distribution:設定視圖沿軸線的排布方式。
  • alignment:設定如何沿軸線垂直方向排布子視圖趴樱。
  • spacing:設定子視圖間距馒闷。
UIStackViewProperties.png

UIStackView適用于iOS 9.0+和tvOS 9.0+,NSStackView適用于macOS 10.9+叁征。這篇文章只講解UIStackView纳账。

使用Stack View時可以先從對象庫中拖拽出Horizontal Stack ViewVertical Stack Viewstoryboard,后把需要添加的視圖放進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 NameStackView翅敌,選擇文件位置羞福,創(chuàng)建工程。

下面通過三個示例來學習Stack View蚯涮。

2. 示例1

打開剛創(chuàng)建demo的Main.storyboard坯临,在First Scene添加以下視圖:第一行為UILabelUISwitch,第二行為兩個UIImageView恋昼。

StackViewD1Storyboard.png

選中第一行的UILabelUISwitch看靠,點擊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距離為20points。如果添加過程遇到問題活孩,你可以點擊這里查看demo物遇,也可以查看上一篇文章學習如何添加約束乖仇。添加完畢后視圖層級如下:

StackViewD1Hierarchy.png

使用Stack View時一般只需要指定堆棧視圖位置,堆棧視圖大小會根據(jù)子視圖大小動態(tài)調(diào)整询兴。

堆棧視圖中子視圖顯示順序由其在arrangedSubviews數(shù)組的順序決定乃沙。在水平堆棧視圖中,視圖顯示方向與閱讀方向一致诗舰,arrangedSubviews數(shù)組中低索引號視圖先顯示警儒。在垂直堆棧視圖中,視圖從上向下顯示眶根,低索引號視圖在上蜀铲,高索引號視圖在下。

當向arrangedSubviews數(shù)組中添加属百、移除視圖時记劝,或視圖被隱藏時,Stack View會自動調(diào)整布局族扰。

下面從UISwitch連接出一個IBAction的屬性厌丑,當點擊UISwitch時,調(diào)整imageStackViewaxis渔呵。imageStackViewstoryboard中圖片堆棧視圖的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)扩氢。

StackViewD1AxisChange.gif

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堆棧視圖迟螺。堆棧視圖與LeadingTrailing舍咖、Top矩父、Bottom距離分別為00排霉、Standard Value窍株、Standard ValueStack View其它屬性如下:

  • Axis:Horizontal
  • Alignment:Center
  • Distribution:Fill Proportionally
  • Spacing:0
StackViewD2Stroyboard.png

上面的DistributionFillFill Equally球订、Fill Proportionally后裸、Equal SpacingEqual Centering五個屬性冒滩,這五個屬性的區(qū)別:

  • UIStackViewDistributionFillStack 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屬性前會有一個+杭攻。

StackViewD2Attributes.png

點擊這些+,可以自定義水平疤坝、垂直堆棧視圖的屬性兆解。下面添加一個當寬度為compact、高度為regularaxis為垂直的屬性卒煞。

StackViewD2AttributesAxis.png

你還可以通過相同方式痪宰,添加一個當寬度為compact、高度為regularspacing屬性畔裕,一般不需要添加其它屬性衣撬。

現(xiàn)在運行app,當豎屏時扮饶,堆棧視圖的axis是垂直的具练;當橫屏時,堆棧視圖的axis是水平的甜无。

StackViewAxis.gif

4. 示例3

Stack View主要優(yōu)點之一是會自動為其每個子視圖創(chuàng)建自動布局約束扛点,也可以對這些子視圖的大小和位置進行設置。

為剛創(chuàng)建的demo添加一個View Controller岂丘,并連接到選項卡控制器陵究,設定Bar Item的標題為Third

打開Third Scene奥帘,自上而下添加UILabel铜邮、UIImageViewUIButton寨蹋,并插入到一個垂直堆棧視圖中松蒜。堆棧視圖屬性設置如下:

  • Axis: Vertical
  • Alignment: Center
  • Distribution: Equal Spacing
  • Spacing: 0
StackViewD3Stroyboard.png

其中UIImageViewcontentModeAspect Fit,為上面Stack View添加約束已旧,與Leading秸苗、TrailingTop距離分別為0运褪、0惊楼、20

在上圖Add Star下面添加一個水平堆棧視圖秸讹,屬性設置如下:

  • Axis: Horizontal
  • Alignment: Center
  • Distribution: Fill Equally
  • Spacing: 10

完成后為其添加約束胁后,與LeadingTrailing嗦枢、TopBottom距離分別為0屯断、0文虏、Standard Value侣诺、20,高度為120氧秘。

StackViewD3StoryboardFinal.png

雖然UIStackView繼承自UIView年鸳,但它只管理子視圖的位置和大小,不提供用戶界面丸相,也就是有些屬性不適用于UIStackView搔确,如backgroundColor,也不能重寫drawRect:方法灭忠。

堆棧視圖中有subviewsarrangedSubviews兩個屬性膳算,其遵守以下規(guī)則。

  • Stack ViewarrangedSubviews數(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連接出一個名為addStarIBAction點擊事件咸产。當點擊時矢否,在底部的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)在增加移除五角星的功能脑溢。從對象庫拖拽一個UIButtonAdd Star下方僵朗。選中UIButtonAdd Star,點擊Embed In Stack按鈕插入堆棧視圖屑彻。修改剛插入堆棧視圖屬性如下:

  • Axis: Horizontal
  • Alignment: Center
  • Distribution: Equal Spacing
  • Spacing: 10

剛添加UIButton標題為Remove Star验庙,文字顏色為red

StackViewD3Remove.png

為剛添加的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)整布局。

StackViewD3.gif

總結(jié)

通過這篇文章藤巢,可以看到UIStackView極大降低了用戶界面開發(fā)難度搞莺,簡化了許多工作,僅僅添加少量約束便可實現(xiàn)自動布局掂咒。在布局時才沧,應該優(yōu)先考慮使用Stack View來布局界面。

Demo名稱:StackView
源碼地址:https://github.com/pro648/BasicDemos-iOS

參考資料:

  1. Stacks
  2. iOS 9: Getting Started with UIStackView
  3. What are the different UIStackView distribution types?

歡迎更多指正:https://github.com/pro648/tips/wiki

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绍刮,一起剝皮案震驚了整個濱河市温圆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌录淡,老刑警劉巖捌木,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嫉戚,居然都是意外死亡刨裆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門彬檀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帆啃,“玉大人,你說我怎么就攤上這事窍帝∨耍” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵坤学,是天一觀的道長疯坤。 經(jīng)常有香客問我,道長深浮,這世上最難降的妖魔是什么压怠? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮飞苇,結(jié)果婚禮上菌瘫,老公的妹妹穿的比我還像新娘。我一直安慰自己布卡,他們只是感情好雨让,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忿等,像睡著了一般栖忠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天娃闲,我揣著相機與錄音虚汛,去河邊找鬼。 笑死皇帮,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蛋辈。 我是一名探鬼主播属拾,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冷溶!你這毒婦竟也來了渐白?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逞频,失蹤者是張志新(化名)和其女友劉穎纯衍,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苗胀,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡襟诸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了基协。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歌亲。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖澜驮,靈堂內(nèi)的尸體忽然破棺而出陷揪,到底是詐尸還是另有隱情,我是刑警寧澤杂穷,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布悍缠,位于F島的核電站,受9級特大地震影響耐量,放射性物質(zhì)發(fā)生泄漏飞蚓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一拴鸵、第九天 我趴在偏房一處隱蔽的房頂上張望玷坠。 院中可真熱鬧,春花似錦劲藐、人聲如沸八堡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兄渺。三九已至,卻和暖如春汰现,著一層夾襖步出監(jiān)牢的瞬間挂谍,已是汗流浹背叔壤。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留口叙,地道東北人炼绘。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像妄田,于是被迫代替她去往敵國和親俺亮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容