Stack View 的开始

作为一名刚刚入门 iOS 开发的人来说,理解并熟练使用 Auto Layhout 非常重要。开始接触自动布局是非常困难和复杂的,布局一个视图通常需要添加非常多的约束,尤其是在创建动态视图时,我们要不断的重复添加和删除约束以达到我们想要的效果。而使用 Stack View 可以很大程度上简化我们频繁调试约束的过程。

通常,我们在创建用户界面的时候很多视图是程线性排列的。以下面这个界面为例,界面中包括非常多的子视图 label,它们是垂直 vertically 线性排列的。

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 3.06.19 PM.png)

当用户界面像上图这样程线性排列的时候,就可以考虑使用stack view了,它是一个 UIStackView 的实例,用来创建垂直或水平的布局。不仅简单实现布局,而且可以帮助你管理不同 View 的各种约束。在理想状态下,你还可以将另外一个 StackView 嵌入到 StackView 中,得益于这个特性,我们可以极大的缩减在布局用户界面时花费的时间。

接下来,我们将创建一个对用某个 model 元素的 Detail 视图来了解一些关于 stack view 的特性。首先,创建一个新的项目,从库中拖拽一个 Vertical Stack View 到 Storyboard 中默认的 ViewController 中。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 3.32.30 PM.png)

为其添加 leading 和 trailing margins 的约束,以及 top 和 bottom 的约束,边距可以设置为 8 point。让它充分填满屏幕。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 3.37.14 PM.png)

拖拽四个 UILabel 到刚刚创建的 stack view 中。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 3.41.27 PM.png)

你会发现所有的 Label 四周都被标记红色辅助线(在 Auto Layout 中的错误提示),在这里意味着这些 Label 存在不明朗的垂直布局。我们有两种方式解决这个问题,既可以使用 Auto Layuout,也可以通过修改 StackView 的一些属性。这里我们先尝试使用 Auto Layout 来解决这个问题,同时方便理解一些用好 Auto Layout 必备的知识点。

解决这个问题我们先要理解一个基本概念,叫做intrinsic content Size , 如果你没有指定某一个子视图的 width 和 height 的约束,那么这个视图将通过自身内容的大小来决定自己的大小。比如一个 UILabel, 当它需要被绘制在屏幕上时发现自己没有 width 和 height 的约束,那它将通过自己的字体大小,text 长度等属性自行判断自己的宽和高。但这会带来一个问题。试想如下图的这种状况:

![两个水平对齐的 UILabel](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 3.54.39 PM.png)

如果这两个 Label 的 superView 发生变化,哪个 Label 会变得更宽?第一个?第二个? 或者两个一起?

这个时候我们就需要使用每一个 View 都拥有的 content hugging prioritiescontent compression resistance priorities 来决定视图被拉伸或压缩的优先级。

  • 其包括下面四种优先级属性:

horizontal content hugging priority
vertical content hugging priority
horizontal content compression resistance priority
vertical content compression resistance priority

对于上面水平对齐两个 Label, 如果其中一个 Label 的 horizontal content hugging priority 优先级更高,更不容易被拉伸,你可以想象优先级更高的 Label 内部有一种力量,像是一个皮筋,从两端向中心发力。在 superView 变宽的时候强迫自己 hold 住现在的身段。

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 4.22.11 PM.png)

现在你已经对 content hugging priority 有了简单的了解,我们现在来思考一下 content compression resistance priority 的作用,它决定了一个 View 有多大的力量抵抗被压扁。

同样是上面两个水平对齐的 Label。这次的场景不是 superView 变宽,而是变窄了,哪个 Label 会被压缩?

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 4.32.10 PM.png)

如果其中一个 Label 拥有更高的 content compression resistance priority 优先级,那么它将更能抵抗住被压扁,对于 Label 来说,更不容易出现上图那样文字显示不全的情况。

好啦,针对 View 的 模糊约束介绍到这里,有了这个概念,解决最开始 四个 Lable 的问题就变的很简单了。

我们选择 Date Created label 打开它的 size inspector 界面,也可以使用快捷键 option + cmd + 5 在这里就可以看到关于这个 view 的压缩和拉伸优先级设置的界面了,这里 xcode 已经设置了相同的默认数值。

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 4.46.46 PM.png)

我们修改 Vertical Content Hugging Priority 值为 249, 这样,它上面的另外三个 label 就拥有了同样且更高的优先级,意味着它们三个更有力量保持自己本身的高度,而 Data Created label 因为自己的力量不够,会被用来填充剩余的屏幕空间。

修改之后,视图布局自动变成下图的状态。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 4.51.48 PM.png)

Ok,问题解决了,接下来我们来看看如何利用 stack view 的特性来解决同样的问题,其实 stack view 拥有一个属性来决定它的子视图的布局样式。

从 storyboard 中选择我们的 stack view(可以在 ViewController 上使用快捷键 shift + cmd + 鼠标右键 来选中)打开它的 attributes inspector 界面,找到最顶部的 stack view 的 section 中的 Distribution 属性。

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.03.01 PM.png)

默认的布局方式为 Fill,它会让其所有的子视图按照其自身的内容大小来决定布局的样式。我们修改它的值为 Fill Equally ,从结果就可以看到,四个 Label 拥有了一样的高度,Fill Equally 会忽略其子视图的自身内容大小来屏幕划分区域*

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.06.52 PM.png)

我们重新 Distribution 属性为 Fill, 这是接下面我们要使用的布局方式。

对于 stack view 来说,最重要的特性就是嵌套,一个 stack view 可以被加入到另外一个 stack view, 在创建复杂的用户界面时,这样的特性非常实用。接下来我们继续丰富我们的界面。

在最顶部的三个 UILabel 的右边都有一个 TextField,我们先完成第一个 name label。首先选择 name label, 选择在 canvas 中右下角的 Auto Layout constraints 菜单中最左边的选项。它会将你选中的视图嵌入到一个新的 stack view。

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.13.25 PM.png)

选择新的 stack view, 打开它的 attributes inspector 界面,其默认的 Axis 布局方向是 vertical, 我们修改为 horizontal

从库中拖拽一个 Text Field 到 name label 的右边。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.18.39 PM.png)
默认设置下,Name Label 拥有更高的 Horizontal content hugging priority 所以,你会看到 Name Label 保持住了自己的宽度,而 text field 被用来填充剩余的空间。而它们的 content compression resistance priority 默认情况下是相同的,这会导致在屏幕宽度变窄的时候,Name Label 仅有的小身板被压缩,我们不希这种情况发生。所以我们要降低 text field 的 Horizontal content compression resistance priority 值,修改为 749。 让 Name Label 有更大的力量抵抗被压扁。

接着,我们希望 name label 和 text field 之间有些间隔,这样看起来会更舒服。 Stack view 可以自定义其中子视图的间隔。
选择 name label 和 text field 所在的 stack view, 打开 attributes inspector,修改其中的 Spacing 为 8 points。注意 text field 会自动缩短,这是因为它抵抗被压缩的能力更低。

接下来,我们将 serial 和 value label 也用同样的方法为期配对 text field。
![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.47.57 PM.png)

添加完成后我们仍然需要进行一些微调,首先我们需要让垂直布局的 stack view 也拥有一些间距,并且三个 label 对应的 text filed 并没有对齐。

选择垂直的 stack view, 也就是我们最开始创建的那个,修改其 Spacing 为 8 point。 选择 Date Created label, 修改其文本排列样式为居中。

接下来是 text field 没有对齐的问题了,其实,stack view 实质上的作用就是用来减少 constraints 的的设置,但某些 constraints 仍然很重要。造成没有对齐的原因就是 text field 前面的 label 的宽度并不一致,而间隔我们设置为同样的数值 8。解决这个问题,我们需要在三个 text field 上添加 leading edge 的约束。

按住 Ctrl 从 Name text field 拖拽到 Serial text field 选择 Leading, 然后对 Serial text field 和 Value text field 做同样的约束添加。 It's Done!

![示例](http://7xrfzx.com1.z0.glb.clouddn.com/2016-03-17-Screen Shot 2016-03-17 at 5.57.15 PM.png)

Stack view 允许你创建非常复杂的用户界面同时又非常便捷高效,不要忘记很多时候 contraints 仍然需要添加,但更多的约束是有 stack view 来管理,而不是你自己。Stack view 还允许你创建动态的用户界面。你可以使用 addArrangedSubView(_:insertArrangedSubview(_:atIndex:)removeArrangedSubview(_:atIndex:) 在 stack view 中添加或者删除某个 view。也可以设置 view 的 hidden 属性 让某个 view 出现和消失,stack view 会识别这个状态,并自动重新布局。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容