共计 6425 个字符,预计需要花费 17 分钟才能阅读完成。
这是对于主动布局的第一篇文章。
>> Stack View 的应用
主动布局 (Auto Layout) 可能依据对视图的束缚(Constraint),动静地计算视图层次结构中所有视图的大小和地位。
基于束缚的 Auto Layout 使咱们可能搭建动静响应外部、内部变动的用户界面。内部变动包含用户扭转窗口大小(OS X)、旋转设施(iOS)、在 iPad 上进入或来到宰割视图(iOS)、不同屏幕尺寸,外部变动包含 app 显示内容长度变动、字体大小变动、对国际化的反对等。
大部分的内部变动会在运行时产生,这就要求 app 要动静的调整视图布局。只管屏幕尺寸不会扭转,但创立一个主动布局的界面就能够实用于 iPhone SE、iPhone 7 Plus、甚至 iPad 不同尺寸屏幕的设施。
当用户界面中视图或控件大小变动时会导致外部变动。如对国际化的反对,把用户界面上的文字扭转为其余语言时,新的语言可能占用不同大小空间;不同的语言有不同布局方向,如英语、中文都是自左向右,而阿拉伯语自右向左,这时中、英文界面右下角的按钮在阿拉伯语中应在左下角。如 app 反对调整字体大小,调整后用户界面中任何文本的高度和宽度都会发生变化,此时须要调整布局。
1. Auto Layout 与 Frame-Based Layout 比拟
布局用户界面形式有三种,第一种是代码形式,第二种是应用 Autoresizing masks,第三种是应用 Auto Layout。
通过代码形式来布局用户界面时须要设定视图在其父视图坐标系中的地位和大小。
为布局界面,你必须计算视图层级中每一个视图的地位和大小。如果其中一个产生了扭转,你就须要再次计算所有受影响的视图。在许多方面,以代码形式构建的界面会更灵便、更弱小。当界面有变动时,你能够操作其它视图的变动。也正因为你须要管制其它视图的变动,构建一个简略的界面可能须要大量工作,构建一个自适应的界面就变的更加艰难。
第二种形式是应用 Autoresizing masks 来构建界面,Autoresizing masks 指定视图如何随父视图的变动而扭转,这简化了适应内部变动布局的复杂度。Autoresizing masks 用于较小数量的可能布局,对于简单的用户界面,须要联合应用代码布局。另外,Autoresizing masks 只实用于内部变动,不响应外部变动。
第三种形式为应用 Auto Layout 增加一系列束缚来构建界面,这些束缚代表两个视图间的关系,最初 Auto Layout 依据这些束缚计算出视图的地位和大小。Auto Layout 动静的响应外部、内部变动。
视图层次结构布局被定义为一系列线性方程。每个束缚示意一个方程。指标是申明一系列方程,最初只有一个可能的布局计划。下图是一个示例方程。
这个束缚示意 Red 视图的 Leading 必须在 Blue 视图 Trailing 后8
points,该方程由以下几局部组成:
- Item 1:方程式中的第一项,这里指 Red 视图。第一项必须是视图或布局参考线(Layout Guide)。
- Attribute 1:在 Item 1 增加束缚的地位。在这里是 Red 视图的Leading。
- Relationship:左右两侧的关系,能够是 equal、greater than or equal 和less than or equal之一。在这里左右两侧相等。
- Multiplier:第二项的值乘以该浮点值。在这里,乘数是
1.0
。 - Item 2:方程式中的第二项,在这里是 Blue 视图。与第一项不同,这一项能够为空。
- Attribute 2:在 Item 2 增加束缚的地位。在这里是 Blue 视图的 Trailing。如果Item 2 为空,这里也要为空。
- Constant:浮点类型的常量。在这里是
8.0
,该值被增加到Attribute 2。
通过创立这样的方程能够创立多种束缚,能够定义两个视图间的间隔,对齐视图、定义两个视图大小关系、定义视图宽高比(Aspect Ratio)。
须要阐明的是下面方程式中的 =
是相等,不是赋值。当 Auto Layout 布局界面时,会计算 Attribute 1 和Attribute 2的值直到等式成立,而不会间接把右侧的值赋值给左侧。因而咱们能够调换等式左右两侧的值,但恪守上面规定的束缚更易于保护。不合乎上面规定的束缚能够通过调换等式两侧解决。
- Multiplier优先应用整数而非分数。
- 常量优先应用负数而非正数。
- 如果可能,视图更应该自上而下,自左向右布局。
束缚既能够用来形容界面中两个视图间的关系,也能够定义一个视图中不同属性间的关系。例如设置视图高度和宽度的高宽比。
在主动布局中,可供束缚的属性有左右高低四边(leading,trailing,top 和 bottom)、宽、高、程度居中和垂直居中等。
2. 创立 demo
这里创立一个 Single View Application 模板的利用,Product Name为 AutoLayout
,Language 为Objective-C,Devices为Universal,抉择文件地位,创立工程。
上面通过几个示例来体验 Auto Layout。
3. 示例 1
关上 Main.storyboard,增加 5 个UILabel
。如下图所示,一个在核心,其余每个角各一个。拖放UILabel
时会呈现蓝色虚线,放在这些蓝色虚线地位。
点击 Xcode 右上角的Assistant editor,这时个别显示的是你所选中视图控制器的代码,点击左上角的Automatic,从弹出菜单中选择Preview > Main.storyboard(Preview)。
能够通过点击上图左下角的 +
按钮增加多个设施的预览,这里只增加 iPhone SE。
通过上图能够看到,在 4 英寸的 iPhone SE 中,只有左上角一个 Label
显示失常。这是因为如果视图没有任何束缚,在 Build Time 零碎会主动为视图增加至左上角、目前大小的束缚。当你增加第一个束缚时,零碎会主动革除所有零碎增加的束缚,此时零碎会呈现红色正告提醒束缚有余。当你增加了一个束缚时,你就须要增加可满足布局的所有束缚。
还记得之前咱们说到的蓝色虚线吗?它们不是这里说到的束缚,它们是 Xcode 提供的布局参考线。
在 Interface Builder 里有三种增加束缚的形式。第一种是在视图间 control
+ 鼠标左键拖拽,也能够在Document Outline 拖拽,在视图间拖拽的益处是弹出菜单会依据拖拽方向扭转。第二种是应用 Align 和Add New Constraints工具,第三种是让 Interface Builder 设置束缚之后咱们批改束缚。主动布局菜单共以下五项:
自左向右顺次为:
- Update Frame:用于在束缚更新后,更新frame。
- Embed in Stack:用于嵌入 Stack View,会依据目前选中视图主动嵌入Horizontal Stack View 或Vertical Stack View。
- Align:用于设置视图程度核心、垂直核心、基线等。
- Add New Constraints:用于设置视图与最近视图、或控制器 Margin 间隔,视图宽、高、宽高比等。
- Resolve Auto Layout issues:增加倡议束缚、删除束缚,其中上半局部对选中视图无效,下半局部对所有视图无效。
选中左上角 Label
,点击Add New Constraints,在弹出的菜单顶部一栏左侧和上部别离填写0
和20
,点击底部 Add 2 Constraints 增加束缚。
用同样形式为另外三个角落处的 Label
增加束缚,束缚均是到间隔本人最近的边缘,其中 Leading 和Trailing为 0
,Top 和Bottom为20
。
应尽量应用
Leading
和Trailing
,防止应用Left
和Right
,这样布局会适应视图的浏览方向。浏览方向随用户设定的以后语言而变,你也能够本人设定。
最初选中视图核心的 Label
,点击Align,勾选弹出窗口中Horizontally in Container 和Vertically in Container选项框,前面数字均为 0
,点击Add 2 Constraints 增加束缚。
当初进入 Preview 查看,一切正常。能够点击红色标记处的旋转按钮,查看 横屏 (Landscape) 状态下 Label
地位、大小。
4. 示例 2
持续在方才的 demo 中进行操作,关上Main.storyboard,从对象库拖拽出一个View Controller,在下面增加两个UIView
,左右各一个,左侧色彩为Blue,右侧色彩为Orange。
两个视图布局束缚是:Blue视图与 Top 和Bottom间隔是 20
,与Leading 间隔 0
,与Orange 视图间隔是 standard。Orange 视图与 Top 和Bottom间隔是 20
,与Trailing 间隔 0
。同时Orange 视图宽度是 Blue 视图宽度的二倍。
因为这里设置 Leading、Trailing、Top 和Bottom束缚与后面雷同,不再叙述。如果遇到问题,能够在我的 Github 中查看。另外,文章底部也会提供 demo 地址。
上面增加两个视图间间距的束缚。选中 Blue 视图,点击 Add New Constraints 按钮,在弹出窗顶部点击 Trailing 文本框内的下三角,抉择 Use Standard Value,最初点击Add 1 Constraint。另外,Standard Value 默认为8
。
当初增加两个视图宽度的束缚。同时选中两个视图,点击 Add New Constraints 按钮,在弹出窗中勾选上图中的 Equal Widths 选项。最初点击 Add 1 Constraint。如果视图呈现黄色正告线,示意以后地位与视图束缚地位不同,点击Update Frames 更新视图地位。
当初增加 Orange 视图宽度为 Blue 视图宽度二倍的束缚。选中任意一个视图,点击底部 =
束缚线,右侧会主动关上 Attribute Inspector,鼠标放在First Item 会看到选中的是 Orange 视图,所以这里的等式为
Orange View.Width = 2.0 x Blue View.Width
所以,批改 Multiplier 为2
。
在 Preview 查看如下,在模拟器查看成果一样。
在 Add New Constraints 一项中顶部有 Constrain to margins 选项框。如果勾选上,束缚增加到父视图的 margin 属性;如果勾销勾选,束缚增加到父视图的 edge 属性。如果在一个控制器上增加一个UIView
,设置背景色为Red,到四边的束缚均为0
,上面第一个图为勾选Constrain to margins,第二个为不勾选。想要理解具体区别,点击这里。
5. 示例 3
持续对示例 2 中的视图进行操作,这次限定 Blue 视图宽度大于或等于 150
。只有当屏幕足够宽时Orange 视图宽度为 Blue 视图宽度二倍才实现,也就是可选实现。
选中 Blue 视图,点击 Add New Constraints 增加宽度为 150
的束缚。放弃 Blue 视图选中状态,关上 Size Inspector,双击Constraints 一栏中宽度为 150
的束缚。也能够单击 Edit 按钮。
双击后弹出如下:
把上图中的 Equal 批改为Greater than or Equal,这样宽度就会大于等于150
。
上图中的 Priority 为束缚优先级。所有束缚默认必须实现 (Required),也能够创立可选实现(Optional) 的束缚。
所有束缚有一个优先级属性,它的值在 1
和1000
间。优先级为 1000
的束缚必须实现,其它优先级的束缚为可选实现。当主动布局计算布局形式时,会优先满足高优先级的束缚。如果不能满足低优先级的束缚,该束缚会被跳过,但被跳过的束缚不是齐全有效,Auto Layout 计算布局计划时会抉择最靠近被跳过束缚的计划。
尽管优先级的值是 1
到1000
,但零碎把优先级划分成了低 (250)、中(500)、高(750) 和必须 (1000) 四类,你只须要把束缚优先级设定为高于或低于这些值一到两个点即可。
当初 storyboard 呈现红色正告,提醒 Blue 视图宽度大于等于 150
与Orange视图宽度为 Blue 视图宽度二倍抵触,把后者优先级设定为 750
。Preview 显示如下:
能够看到,在 iPhone 的 竖屏 (Portrait) 中两个视图宽度简直一样宽,在 横屏 (Landscape) 中,Orange视图宽度是 Blue 视图宽度二倍。即优先满足了 Blue 视图宽度大于等于 150
这一束缚。
6. 示例 4
目前为止,所有示例均用束缚指定视图的地位和大小,但有些视图的大小依据内容变动,这称为固有内容大小 (Intrinsic Content Size)。例如,UIButton
的intrinsic content size是题目大小外加很小 margin。
不是所有的视图都有 intrinsic content size。如:UIView
和NSView
不具备固有内容大小,UILabel
、UIButton
、UISwitch
和 UITextField
高和宽都具备固有内容大小,UIImageView
没有增加图片时不具备intrinsic content size,增加图片后固有内容大小与图片大小统一。
Auto Layout 在每个维度应用一对束缚来示意视图的 intrinsic content size。内容拥抱(Content hugging) 将视图向内拉,使其紧贴内容。内容压缩阻力 (Content Compression Resistance) 将视图向外推,使其内容可能残缺显示、不被压缩。
固有内容大小的束缚有本身的优先级。个别,content hugging优先级为 250
,content compression resistance 优先级 750
。因而,个别拉伸视图比压缩视图容易。例如:你能够把button 拉伸一些,不影响应用。但如果压缩一些,内容可能无奈残缺显示。
持续在方才的 demo 里操作,从对象库拖拽出一个 View Controller,在顶部增加一个UILabel
和一个UITextField
。
增加束缚,让 Label 与Leading间隔为 0
,与Text Field 的Leading间隔为 Standard 值,与 Text Field 基线在同一程度地位;让 Text Field 与Top间隔 20
,与Trailing 间隔为0
。两个视图宽和高均为固有内容大小。
这里增加束缚与后面示例雷同,不再叙述增加过程。只说一下增加基线束缚。选中两个视图,点击Align,勾选Baselines,点击增加Add 1 Constraint。
UILabel
和 UITextField
在一起时,个别 UILabel
放弃本身宽度,拉伸 UITextField
,以此填充可用空间。所以,该当设置UILabel
的content hugging优先级为 251
,UITextField
的为250
。
在 Size Inspector 查看 content hugging,你会发现Interface Builder 曾经设置好了优先级。另外,如果你是用代码增加主动布局,须要手动设定这里的优先级。
点击 Update Frames 更新 frame。在Preview 查看布局。
只有当高为固有内容大小时基线才能够正确对齐。如果高被压缩或拉伸,基线将不能正确对齐。
个别在解决 示例 4
中的束缚时应该应用 Stack View。Stack View 提供了一种轻松的形式利用主动布局的性能,而不会引入简单的束缚,在下一篇文章咱们将具体介绍 Stack View 的应用。
Demo 名称:AutoLayout
源码地址:https://github.com/pro648/Bas…
参考资料:
- Auto Layout Guide
- What is“Constrain to margin”in Storyboard in Xcode 6
欢送更多斧正:https://github.com/pro648/tips
本文地址:https://github.com/pro648/tip…