文章修改
2月1日:添加使用约束
、编辑约束
和iOS特性
三个部分
2月24日:根据本身的理解,修改iOS特性
部分的内容html
Auto Layout,经过设置在View上的约束,动态计算视图层次结构中全部的View的尺寸和位置。举个栗子,你约束一个Button,令它的水平中心线和一个ImageView相同,而且它的上边缘距离ImageView的下边缘有8个像素。若是ImageView的尺寸或者位置改变,Button会自动调整,以符合以前设置的约束。 ios
基于约束的Auto Layout,使咱们搭建可以动态响应内部和外部变化的用户界面。app
外部变化发生于superview的尺寸或者位置改变,好比,less
设备屏幕旋转;ide
支持不一样屏幕大小的设备。工具
这时,全部的View都要从新计算尺寸和位置。每一次变化,都会刷新视图层级结构的布局。这些变化大部分发生在运行时,它们须要APP可以动态响应。布局
内部变化发生于你的界面中的View的尺寸或者位置发生改变。好比,测试
APP中显示的内容的改变,新的内容可能须要一个新的布局。通常,在显示文字或者图片时会出现这种状况;字体
APP支持动态设置。若是用户能够设置字体大小,这将会改变任何与文本相关的控件的高度或者宽度,布局必须可以适应变化。ui
Auto Layout的实现是基于设置在View上的一系列约束的。每一条约束都是一个表达式。
下图是官方文档给的示例图:
这个约束代表,Red View
的左边缘
与Blud View
的右边缘
的距离为8。这个等式由如下几个部分组成:
Item 1 :表达式中的第一个控件。在这个例子中是Red View
;
Attribute 1 :第一个控件的一个属性。在这个例子中是Red View
的leading edge
;
Relationship :表达式左右两边的关系,可使等于
,大于等于
或者小于等于
。在这个例子中,两边的关系是相等的;
Multiplier :和第二个控件的属性相乘的乘数,是一个浮点型。在这个例子中是1.0
。通常状况下,这个值不可置为0.0
;
Item 2 :表达式中的第二个控件。在这个例子中是Blue View
。它是能够为空的,即表达式变成Item 1 * Attribute 1 = 0.0 * NotAnAttribute + Constant
;
Attribute 2 :第二个控件的一个属性。在这个例子中是Blue View
的trailing edge
;
Constant :一个浮点型的常数。在这个例子中是8.0
。
大部分的约束是定义两个控件之间的关系。这些控件必须是View
或者是Layout Guide
。约束也能够定义一个控件的两个属性之间的关系,好比设置一个控件的上边缘到下边缘的距离、左边缘到右边缘的距离,即它的高度或者宽度。当表达式中的Item 2
为空时,它的属性必须被设为Not An Attribute
,而且Multiplier
置为0.0
。
一般状况下,包含四个边(leading,trailing,top和bottom),以及高度(height),宽度(width),水平中心点(CenterY),垂直中心点(CenterX)。文本类型的控件还有一个基线(baseline)属性。
属性说明
Height和Width。这两个属性能够被直接赋值,能够是一个常数,也能够是其余View的Height或者Width值。可是,不能够为负数。
Top、Bottom、Baseline。能够和Top
、Bottom
、Baseline
、CenterY
组合。
Leading和Trailing。能够和Leading
、Trailing
、CenterX
组合。
Left和Right。避免使用这两个属性,而使用Leading
和Trailing
来替代它们。
CenterX和CenterY。CenterX能够和Leading
、Trailing
、Left
、Right
组合。CenterY能够和Top
、Bottom
、Baseline
组合。
上面提到的属性能够分为两类,尺寸相关
和位置相关
。尺寸相关(如height、width)用来定义物件的大小。位置相关(如leading,top)的属性用来代表该物件和其余物件之间的位置关系。使用这些属性时须要注意:
不要使用尺寸相关的属性去约束一个位置相关的属性。
只能够给尺寸相关的属性直接赋值一个常量。
举几个简单的例子:
// 设置一个固定高度 View.height = 0.0 * NotAnAttribute + 40.0 // 设置两个按钮之间的固定距离 Button_2.leading = 1.0 * Button_1.trailing + 8.0 // 让两个按钮的左边缘对齐 Button_1.leading = 1.0 * Button_2.leading + 0.0 // 给两个按钮相同的宽度 Button_1.width = 1.0 * Button_2.width + 0.0 // 让View的中心和父类的中心相同 View.centerX = 1.0 * Superview.centerX + 0.0 View.centerY = 1.0 * Superview.centerY + 0.0 // 设置一个View的宽高比 View.height = 2.0 * View.width + 0.0
约束的设置没有最好的,只有最适合的。
优先级priority
是Auto Layout在计算的时候用到的参数。优先级的值能够是1-1000任意整数。系统定义了low(250)、medium(500)、high(750)和required(1000)四个等级。通常状况下,咱们手动设置的优先级的值也会集中在这四个等级下。
优先级默认值是1000。
关于Auto Layout是如何经过优先级来计算出解决方案,我在看完官方文档后仍是一头雾水。但愿有大神能够指点一二。
在storyboard中有3种方式添加约束。
在View之间使用Control-Drag
;
使用Pin
和Align
工具;
让Interface Builder自动添加约束。
所谓Control-Draging
就是按住Control
键,用鼠标左键拖动
的方式添加约束。这两步操做也能够用按住鼠标右键拖动
来替代。
当释放鼠标左键后,就会弹出一个HUD,显示能够设置的约束。
Interface Builder会根据选择的两个控件以及拖动的方向筛选出能够设置的约束。若是拖动的方向倾向于水平,你能够选择设置水平方向上的间距和垂直方向上的对齐方式。反之,若是拖动的方向倾向与垂直,则能够选择设置垂直方向上的间距和水平方向上的对齐方式。
提示:
能够从一个控件拖动到另外一个控件,设置它们之间的关系。也能够拖动到控件自身,设置宽度和高度;
不只能够在Scene中直接拖动,能够在Storyboard左侧的视图大纲中用一样的方式拖动。在大纲中拖动设置约束,会显示出全部的可选约束,而不会进行筛选;
Control-Dragging能够很是快速得设置约束。这些约束是基于Scene中View的当前的位置,所以在设置约束以前要定位好View。
Interface Builder在Storyboard的编辑窗口的右下角提供四个自动布局的工具,分别是Stack
、Align
、Pin
、Resolve Auto Layout Issues
。
当你想精确控制约束的Constant或者想一次性添加多个约束,可使用Align和Pin工具。使用Align和Pin还有一个好处,咱们不是必需要设置好View的位置,而是只须要定好相对位置,添加约束,而后update frames
。Auto Layout会自动计算出正确的位置。
Stack Tools能够将选中的一个或者多个控件嵌入到一个Stack View中,并会从新计算布局。Stack View是iOS 9添加的新特性。
对于Stack View,我尚未弄明白使用方法,因此这里不讲述。
Align Tools能够快速对齐控件。选择一个或多个你想对齐的控件,而后单击Align Tool
。而后会弹出可选的一系列对齐方式。
选择其中的选项,而后点击Add Constraints
。以后,就会自动添加对齐的约束设置。大部分状况下,会选择两个或者两个以上的View来设置对齐。Horizonally in Container
和Vertically in Container
这两个能够添加到单一的View上。
Pin是大头针的意思。因此这个工具能够用来给View定位。它可让咱们快速设置一个View相对于它周边View位置或者它的宽高。选择一个你想对其进行定位的View,单击Pin Tool
,会弹出以下的窗口。
窗口的上半部分,能够设置选中的View的Top,Bottom,Leading,Trailing与相邻最近的View的间距。最初显示的数字是当前的间距。咱们能够输入一个自定义的值,还能够点击输入框右边的倒三角,在弹出的下拉菜单中选择参照的View。关于Constrain to margins
选项,若是选中,会将父视图的外边距做为间距的值的参考。
下半部分能够设置宽高相关的属性。宽和高默认的是Scene中的尺寸,也能够自定义值。宽高比的默认值也是根据Scene中的尺寸进行计算。若是想自定义的话,只有在设置完宽高比以后修改这个约束。
通常状况下,选择一个View,对它进行定位。选择两个及其以上的View设置Equal Height
或者Equal Width
。使用Pin Tool设置完约束后,可能须要Update frames
。
Resolve Auto Layout Issues提供一些解决Auto Layout问题的方法。上半部分只针对选中的View,下半部分则针对Scene中全部的View。
咱们能够
根据当前约束更改frame;
根据当前frame更改约束的设置;
添加缺乏的约束;
清除已添加的约束;
设置系统推荐的约束。
这些功能字面上写得很清楚,具体的效果你们能够用简单的Demo来看一下。
Interface Builder能够为咱们建立部分或者所有的约束。根据所提供的View的尺寸和位置,它会推断出最好的约束。前提是,咱们必须肯定View的位置并再也不更改。一个小小的间距的改变,可能对于整个布局来讲确实巨大的。
若是想让Interface Builder来完成约束的添加,单击上文提到的Resolve Auoto Layout Issues
工具,点击Reset to Suggested Constraints
。Interface Builder就会为已选的(也能够是Scene中所有的)View建立合适的约束。
另外,咱们能够本身添加一部分约束,而后选择Add missing Constraints
,让Interface Builder来添加剩下的所需的约束。
这种方法能够快速完成约束的设置。可是,有可能运行获得的UI并非你想要的。要不断地测试UI,修改约束,以达到最终想要的效果。
添加约束以后,须要可以找到它、查看它、编辑它。
编辑窗口会显示做用于当前选择的View的约束。经过线的形状
、颜色
和类型
说明当前约束的当前状态。
I-bars(两端是T型的线):I-bars显示间距的大小。多是两个控件之间的大小,多是一个控件的高度或者宽度。
Plain Line(一条普通的直线):Plain Line显示控件边缘的对齐方式。例如,两个或两个之后的控件是左对齐的,那么,这条线会链接着这些控件,而且与它们的Leading之间的间距为0。
Solid Line:实线表示这个约束是Required,即priority == 1000。
Dash Line:虚线表示这个约束是Optional,即priority < 1000。
Red Line:红线表示被约束的影响的控件的约束设置有错误。具体的缘由能够点击大纲中每一个Scene的右边的箭头查看。这时,箭头是红色的。
Orange Line:橘黄色的线代表,Auto Layout根据已有约束计算出来的frame和当前Scene中设置的frame不一样。这时,大纲中的右边的箭头是黄色的。能够用Resolve Auot Layout Issues
-> Update frames
来进行修正位置。
Blue Line:蓝色的线表示当前的约束设置是正确的,而且控件的位置和Auto Layout计算出来的位置是同样的。
Equal Badges:相等标记代表两个控件的宽度或者高度是相同的。而且标记中包含=
符号。
Greater-than-or-equal and less-than-or-equal badges:和Equal Badges相似,它们是标记约束的关系是大于等于或者小于等于的,同时也会显示对应的符号。
全部添加的约束都陈列在大纲里。这些约束以伪代码的形式呈现。当选择一个约束时,会在Scene中高亮显示,能够帮助咱们快速找到它。并且,能够在右侧的Show the Size inspector
下对约束的Constant
、Priority
、Multiplier
、Relation
、Identifier
、Placeholder
属性进行编辑。
一旦UI变得复杂以后,咱们用这种方式找约束就会显得很吃力。Show the Size inspector
工具能够显示出在当前选中的控件上添加的约束。约束的一部分属性也能够在这里进行修改。
注意:这里虽然都是在Show the Size Inspector
下进行修改,可是前者是选择一个约束,后者是选择一个控件。
iOS在与Auto Layout方面有一些独有的特性,包括top and bottom layout guides
、Layout Margins
。
top and bottom layout guides表示当前的ViewController从最上面到最下面的可见范围。若是不但愿显示的内容在UIKit bars
(例如status bar,navigation bar,tab bar)下面,那么就能够和上下的layout guide来设置约束。
layout guides是遵照UILayoutSupport
协议的。这个协议有一个length
属性,来表示guide和root view(root view就是ViewController默认添加的view)边缘的距离:
对于top layout guide,length指明ViewController的root view的上边缘和覆盖在root view上的bar(例如status bar和navigation bar)的底部的距离。
对于bottom layout guide,length指明ViewController的root view的下边缘和覆盖在root view上的bar(例如tab bar)的顶部的距离。
在iOS 9中,guide也能够像控件同样,支持用top
、bottom
、height
设置约束。好比,用top layout guide的bottom
属性和bottom layout guide的top
属性与view设置约束。UILayoutSupport
还提供了topAnchor
、bottomAnchor
、heightAnchor
属性,可让咱们用代码的形式来设置约束。
若是layout guides
是view最近的"控件",那么系统会自动将layout guides
做为设置约束的对象。当使用Pin Tool时,能够在layout guides
和root view的上下边缘
进行选择。
Auto Layout为每个view都定义了margin。margin指的是控件显示内容部分的边缘和控件边缘的距离。就像“回”这个汉字同样,外面的“口”就是控件的外边缘
,里面的“口”是控件显示内容的部分的边缘,我暂且称它为内边缘
,这两个边缘之间的距离就是margin
。
能够用layoutMargins
或者layoutMarginsGuide
属性得到view的margin。layoutMargins
容许获取或者设置UIEdgeInsets
结构的margin,layoutMarginsGuide
则只会获取到只读
的UILayoutGuide对象。
每个view的默认的margin是8。能够根据APP的须要进行修改。__系统给ViewController的root View设置的margin则不能修改__。root View的上下的margin为0,左右的margin为20。
当使用Control-Dragging
方式,给一个View和它们父视图设置约束时,默认使用内边缘,而不是外边缘。当使用Pin Tool
时,若是Constraint to margins
被勾选,则会使用父视图的内边缘
做为设置约束的参照,若是没有被勾选,则使用外边缘
做为设置约束的参照。所见到的效果就是两种参照下的约束的Constant
的值相差一个margin
。
当在Interface Builder中编辑约束时,First Item
和Second Item
的弹出菜单中能够选择Relative to margin
。若是勾选,会在top
、leading
等属性后面加上Margin
,变成topMargin
、leadingMargin
等,意味着约束的设置参照View的内边缘而不是外边缘。
官方文档为咱们提供了一些设置约束时的建议
__在最相近的两个控件之间建立约束。__假若有3个Button,分别是first,second,third。能够约束first的右边缘和second的左边缘的距离,second的右边缘和third的左边缘的距离。而不要约束first的右边缘和third的左边缘距离,中间隔了一个second。
__避免设置固定的高度和宽度。__Auto Layout是动态响应布局的变化。一个控件若是设置固定尺寸,那么就会失去自动调整的能力。
在update frames
时注意,若是这个控件没有设置足够多的约束来肯定它的位置和尺寸,那么可能会致使一些意想不到的后果。好比会跑到屏幕外,或者由于宽度、高度为0而消失等等。
给全部的控件取一个有意义的名称。在使用工具时,能够方便地辨别出View。
使用leading
和trailing
代替left
和right
。
当使用代码建立约束时,确保将它们的translatesAutoresizingMaskIntoConstraints
属性为NO
。默认状况下,系统会基于控件的frame自动建立一系列约束。当你添加本身的约束时,不可避免地会和自动生成的约束产生冲突。
参考内容:
苹果官方文档:Auto Layout Guide
本文中的图片均取自苹果官方文档