作者:Umberto Raimondi,原文鏈接,原文日期:2015-12-08
譯者:CoderAFI;校對(duì):Channe姆吭;定稿:shanks
示例程序采用 Swift2.0 編寫,需要用 Xcode7 進(jìn)行編譯唁盏,可以訪問 Github 或者 zipped 下載本文源代碼
iOS9 新加入了一個(gè)非常易用的布局控件 UIStackView内狸,它可以將一組 UIView 視圖進(jìn)行垂直或水平方向的排列,用來(lái)替換手工使用 Auto Layout 對(duì)視圖進(jìn)行布局升敲。
每個(gè) UIStackView 控件都可以在垂直和水平方向上排列展示一組 subviews答倡,并可以根據(jù)當(dāng)前屏幕大小和方向的變化動(dòng)態(tài)調(diào)整它的內(nèi)容,感覺起來(lái)就像是一個(gè)隱形的容器驴党。實(shí)際上 subviews 的位置是根據(jù)設(shè)置的對(duì)齊瘪撇、間距和大小屬性來(lái)決定的。
內(nèi)部的原理是 UIStackView 類幫你管理了 Auto Layout 約束港庄。想象一下 UIStackView 其實(shí)就是一個(gè)基于 Auto Layout 的抽象層從而使布局屬性的創(chuàng)建簡(jiǎn)單化倔既。你可以在一個(gè)主 UIStackView 中嵌套 UIStackView 從而讓視圖精確放置到相應(yīng)的位置。
如果你做過 Android 開發(fā)鹏氧,你會(huì)發(fā)現(xiàn) UIStackView 概念跟 Android 中最常用的布局控件 LinearLayout 非常相似渤涌,這些布局的想法其實(shí)都是從早期的 Java Swing 開發(fā)中借鑒過來(lái)并加以完善的。
基礎(chǔ)
UIStackView 既可以用代碼編寫也可以在 Interface Builder 中設(shè)計(jì)把还。
在 Interface Builder 中你可以從 Object Library 控件選擇工具集里找到垂直或者水平對(duì)齊的 UIStackView 并添加到相應(yīng)位置实蓬,然后就可以在 UIStackView 上添加新的視圖了茸俭。
UIStackView 同樣也可以對(duì)現(xiàn)有的一些視圖進(jìn)行包裝,只需要選擇他們并點(diǎn)擊 Interface Builder 底部工具欄新加的圖標(biāo)即可安皱。
非常簡(jiǎn)單调鬓,但是我們的教程將用代碼的方式實(shí)現(xiàn)一個(gè)簡(jiǎn)單的嵌套布局。
在這個(gè)簡(jiǎn)單的示例程序中酌伊,我們將會(huì)在狀態(tài)欄下放置一個(gè) UIStackView腾窝,里面包含四個(gè)控件:兩個(gè) UILabel,一個(gè)水平方向的 UIStackView 和 一個(gè) UIButton居砖。水平方向的 UIStackView 中包含了三個(gè)帶有默認(rèn)圖標(biāo)的按鈕虹脯。
下面讓我們創(chuàng)建一個(gè) Single View Application,記住要將 Deployment Target 設(shè)置成 9.0+奏候。
打開 ViewController
類并用下面的代碼替換 viewDidLoad
方法:
var stackView:UIStackView!
var nestedStackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
stackView.translatesAutoresizingMaskIntoConstraints=false
self.view.addSubview(stackView)
// Main UIStackView contraints, nearly fills its parent view
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-30-[stackView]-30-|",options: NSLayoutFormatOptions.AlignAllLeading,metrics: nil, views: ["stackView":stackView]))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[stackView]-10-|",options: NSLayoutFormatOptions.AlignAllLeading,metrics: nil, views: ["stackView":stackView]))
stackView.axis = .Vertical
stackView.alignment = .Fill
stackView.spacing = 25
stackView.distribution = .FillEqually
var lbl = UILabel()
lbl.text ="Label 1"
lbl.backgroundColor = UIColor.redColor()
stackView.addArrangedSubview(lbl)
lbl = UILabel()
lbl.text = "Label 2"
lbl.backgroundColor = UIColor.greenColor()
stackView.addArrangedSubview(lbl)
nestedStackView.axis = .Horizontal
nestedStackView.alignment = .Fill
nestedStackView.spacing = 25
nestedStackView.distribution = .FillEqually
nestedStackView.addArrangedSubview(UIButton(type: .InfoDark))
nestedStackView.addArrangedSubview(UIButton(type: .InfoLight))
nestedStackView.addArrangedSubview(UIButton(type: .ContactAdd))
stackView.addArrangedSubview(nestedStackView)
let btn = UIButton(type: .System)
btn.setTitle("Press Me", forState: .Normal)
stackView.addArrangedSubview(btn)
}
為了指定主 UIStackView 是垂直方向布局的我們把 axis
屬性設(shè)置成 .Vertical
循集,前三個(gè)控件將會(huì)等間距排列,剩下的UIButton會(huì)填充剩余的可用空間蔗草。在嵌套 UIStackView 中的三個(gè)默認(rèn)按鈕也是用同樣的方式來(lái)排列暇榴。alignment
、distribution
蕉世、spacing
三個(gè)屬性會(huì)在下面單獨(dú)講解,這里我們先忽略它們婆硬。
有時(shí)候你可能需要將部分視圖隱藏起來(lái)或者顯示出來(lái)狠轻,這對(duì)于 UIStackView 來(lái)說(shuō)實(shí)現(xiàn)起來(lái)是非常容易的,你只需要設(shè)置相應(yīng)視圖的 hidden
屬性就可以彬犯。
為了方便測(cè)試向楼,我們給 UIButton 添加一個(gè) pressedMe
的點(diǎn)擊事件響應(yīng)方法:
...
btn.setTitle("Press Me", forState: .Normal)
btn.addTarget(self, action: "pressedMe:", forControlEvents: UIControlEvents.TouchUpInside)
stackView.addArrangedSubview(btn)
}
func pressedMe(sender: UIButton!){
UIView.animateWithDuration(0.5) {
self.nestedStackView.hidden = !self.nestedStackView.hidden
}
}
當(dāng)點(diǎn)擊這個(gè)按鈕時(shí),主 UISTackView 和 內(nèi)部的 UISTackView 將會(huì)根據(jù)在 viewDidLoad
中設(shè)置的屬性重新布局內(nèi)部的子視圖并帶有短暫的顯示或者隱藏動(dòng)畫效果谐区。
如果需要湖蜕,subviews 也可以完全從 UIStackView 中移除然后剩下的子視圖也會(huì)根據(jù)各自的屬性重新布局。
func pressedMe(sender: UIButton!){
stackView.removeArrangedSubview(nestedStackView)
nestedStackView.removeFromSuperview()
}
這個(gè)移除的操作需要兩步宋列,第一步是調(diào)用 removeArrangedSubview
方法用來(lái)從 UIStackView 刪除視圖并且重新布局剩余的 subviews 但是實(shí)際上并沒有從父視圖上刪除昭抒。第二部就是調(diào)用 removeFromSuperview
方法以保證該視圖從父視圖中完全的被刪除。
UIStackView: Alignment, Distribution And Spacing 屬性
下面讓我們?cè)敿?xì)了解下 UIStackView 的布局屬性:
Axis 軸
定義子視圖的布局方向炼杖,包含 Vertical(垂直) 和 Horizontal(水平)兩個(gè)枚舉值灭返。
Alignment 對(duì)齊
alignment 屬性指定了子視圖在布局方向上的對(duì)齊方式,如果值是 Fill 則會(huì)調(diào)整子視圖以適應(yīng)空間變化坤邪,其他的值不會(huì)改變視圖的大小熙含。有效的值包含:Fill、 Leading艇纺、 Top怎静、 FirstBaseline邮弹、 Center、 Trailing蚓聘、 Bottom腌乡、 LastBaseline。
Distribution 分布
Distribution 屬性定義了 subviews 的分布方式或粮,可以賦值的5個(gè)枚舉值可以分為兩組: Fill 組 和 Spacing 組导饲。
Fill 組用來(lái)調(diào)整 subviews 的大小,同時(shí)結(jié)合 spacing 屬性來(lái)確定 subviews 之間的間距氯材。
Fill: subviews 將會(huì)根據(jù)自己內(nèi)容的內(nèi)容阻力(content resistance)或者內(nèi)容吸附優(yōu)先級(jí)(hugging priority)進(jìn)行動(dòng)態(tài)拉伸渣锦,如果沒有設(shè)置該值,subviews 中的一個(gè)子視圖將會(huì)用來(lái)填充剩余可用空間氢哮。
FillEqually: 忽略其他的約束袋毙,subviews 將會(huì)在設(shè)置的布局方向上等寬或等高排列。
FillProportionally: subviews 將會(huì)根據(jù)自己的原始大小做適當(dāng)?shù)牟季终{(diào)整冗尤。
Spacing 組指定了 subviews 在布局方向上的間距填充方式听盖,當(dāng) subviews 不滿足布局條件或有不明確的的 Auto Layout 設(shè)置時(shí),該類型的值就會(huì)結(jié)合相應(yīng)的壓縮阻力(compression resistance) 來(lái)改變 subviews 的大小裂七。
EqualSpacing: subviews 等間距排列
EqualCentering: 在布局方向上居中的 subviews 等間距排列
Spacing 間距
spacing 屬性根據(jù)當(dāng)前 distribution 屬性的值有不同方向的解釋皆看。
如果 UIStackView 的 distribution 屬性設(shè)置的是 EqualSpacing、 EqualCentering背零,spacing 屬性指的就是 subviews 之間的最小間距腰吟。相反如果設(shè)置的是 FillProportionally 屬性,那么 spacing 的值就是嚴(yán)格的間距值徙瓶。
iOS7+ 兼容
官方的 UIStackView 只在 iOS9 以上系統(tǒng)可以使用毛雇,但是其他的開源組織在低版本的系統(tǒng)上也實(shí)現(xiàn)了相應(yīng)的功能:
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán)侦镇,最新文章請(qǐng)?jiān)L問 http://swift.gg灵疮。