这些截取自《IOS开发完全上手》+部分自己的见解
PS:感觉有些概念问题还是要了解一点的
自动布局前言
iPhone和iPod touch设备上的应用程序可以纵向或横向显示内容,并且设备配有3.5英寸或4英寸显示屏。这导致4中不同的布局:两种不同小屏幕尺寸下的纵向和横向布局。
即使使用Visual编辑器(可视化编辑器),创建支持4中不同布局的应用程序也是一项挑战,尤其是当有动态的屏幕元素时,甚至当语言变化时也会使用不同长度的标签。其结果可能是大量的定制代码,以及针对故事版上同一界面的多个视图控制器
自动布局是基于约束的引擎,可以让你描述视图之间的关系。自动布局接收这些描述或约束,并计算出如何跟当前屏幕大小和方向放置应用程序视图并确定其大小。有了它,就可以为一个界面只创建一个视图控制器并且掌控代码。
在接下来的几个小节里面,将会介绍如何将自动布局纳入应用程序的设计和开发过程中。将首先探索自动布局的关键概念,并利用它们为Add/View场景设计约束。接下来,通过修改Add/View界面来使之能工作在全部两种屏幕尺寸的纵向屏幕上。可以使用实用的设计、布局和调试技巧实现这一点。最后,你会创建自己的约束并借助动态更新控制器约束的功能来增加对横向屏幕的支持
自动布局的基本知识
当只有一种方向的一种屏幕尺寸时,设计场景时指确定哪些视图元素是需要的,然后将这些元素放置在视图中,或放置在视图层次结构里。添加旋转功能会增加复杂性,但扔然是可控的。而一旦除了添加界面方向之外还增加不同的屏幕尺寸,事情就会变得更加复杂。早期版本的IOS提供了一些灵活性,让你指定当视图的容器改变大小时,它们如何自我调整。但通常,具有视图依赖性或稍微复杂的视图层次的布局需要编写代码。往往这些代码需要做复杂计算,并且更新许多视图。
例如,考虑在不同高度的纵向屏幕上运行应用程序。我们需要知道高度差,哪儿个视图可以移动/或调整打下,以及它们可以移动和/或调整大小到多大程度。然后,我们需要选择哪儿个视图来实际地移动和/或调整大小。如果高度差异要求移动多少个视图,那么我们很可能需要编写代码。
纵向和横向之间的旋转更加复杂。问题也更大。
例如,前面几节做的CarValet,我们做个旋转,然后变成这个样子。
可以自己试试看。想一下,将设备旋转为横向,然后再恢复的过程中,单个视图元素如何移动。注意发生了多少起移动。可以看到,在不断变化的环境中发生了很多事情。每个视图都经过多个步骤。尽管中间步骤已经自动为我们做好,但最好想象一下计算每个视图的最终位置和大小。可能有太多的重新计算,使得这样做不如创建一种不同的布局。
现在假设我们的布局是4英寸的屏幕创建,我们现在要检测3.5英寸的屏幕,计算出大小差异,移动按钮并调整汽车信息标签。实现这一种变化的一些伪代码如下:
if (!is4InchDisplay && (deltaHeight > 0.0) {
carInfoLabel.frame.size.height = deltaHeight / 2.0;
previousButton.frame.origin.y -= deltaHeight;
editButton.frame.origin.y -= deltaHeight;
nextButton.frame.origin.y -= deltaHeight;
}
这并不是有效的Objective-C代码,真实代码会更长。即使是伪代码,也为这个简单的实例做了很多工作,而且目前并不容易清楚这些代码的作用。更糟的是,对可视化布局的所有变更都要求修改代码。
对我们来说,描述视图之间如何关联,或再当前这种情况下视图分组之间如何关联,是更容易的。以下使用三个视图分组:添加汽车视图分组包含汽车总数标签和增加汽车按钮,分隔符视图只包含本身,而查看汽车视图分组中包含其余的元素。
- 添加汽车视图分组的高度是固定的,该高度是指它距离容器顶部的iOS标准距离
- 分隔符视图到它的容器的顶部有固定的距离,并且有固定的高度
查看汽车视图分组到容器视图的底部和两侧为标准距离,而顶部到分割符视图为固定距离
这些描述创建可以根据屏幕高度增大或缩小的查看汽车视图分组。“标准距离”指的是苹果公司建议的内凹和空间。由于查看汽车视图分组可以变化,因此需要制定组成视图之间加何关联。Car Info标签距离顶部和底部有足够的空白,可以根据屏幕搞懂调整大小:
Car Number标签固定到其容器视图(查看汽车视图分组)的顶部
- 每个按钮都固定到其容器视图的底部
Car Info标签的顶部到Car Number标签的底部为标准距离,而底部到Previous按钮的顶部为标准距离
当查看汽车视图分组增大或缩小时,Car Number标签和按钮保持固定。Car Info标签会根据需要来改变高度。使用其他一些描述,可以指定整个场景。
有了自动布局,可以创建这些类型的描述,iOS会用它们来弄清楚如何根据当前屏幕大小放置视图以及调整视图大小。系统需要解决让界面适配不同屏幕高度和方向的问题。我们设置可以强制系统重新计算,例如在视图被扩展或插入时。
关系是关于用户界面(UI)元素的一个属性如何关联到另一UI元素的属性的约束。表达两个视图之前的所有关系需要一个以上的约束。对于自动布局的全部功能,只有一些新的方法和类NSLayoutConstraint用于描述这些约束。
约束
之前介绍的描述是关于视图间关系的约束。有时关系包含在同一视图内,有时在相邻视图之间,有时在视图与其容器之间。甚至可以指定不同容器中视图之间的关系。例如,可以说New Car按钮与Previous按钮具有相同的宽度。
像素和点
查看约束之前,理解像素和点之间的区别是很重要的。像素是屏幕上可用于显示的单独彩色元素的物理硬件可寻址组件。它们决定了屏幕的分辨率,以及在给定区域的像素数或像素密度,决定物体在屏幕显示的锐利程度。
到目前为止,iOS单位配备了两种像素密度,分别针对正常屏幕和Retina显示屏。因为Retina显示屏有两倍的像素密度,会出现像素在正常显示屏上正确显示,但在Retina显示屏上只有一半大小的情况。正确放置其他屏幕元素时(比如视图)也会遇到类似的问题,况且将来会有许多不同的像素密度的屏幕。编写代码来处理所有可能情况将花费很大工夫。
相反,苹果公司使用点——在屏幕绘图区域内的一种像素无关的表示。它们能够处理所有的困难工作。屏幕上的坐标、元素之间的距离、约束的值都以点了表示,而不是像素;而且图像可以提供正常屏幕和Retina显示屏两种版本。
约束关系
最简单一种约束与视图本身的特性相关,如44点的固定高度。可以用如下方程表达这种约束
view1.height == 44.0
更常见的是一个视图的属性与另一个视图的属性之间的关系,例如视图1的顶部与视图2的底部的位置是相同的:
View1.top == View2.bottom
仔细看看这两种约束关系。它们没有使用赋值运算符=,而是使用相等运算符==。这是约束的重要组成部分。它们不是赋值。系统可以通过改变语句的某一侧或两侧来找到解决方案。例如,在上面的关系中,系统可以改变视图1的顶部和视图2的底部。稍后将看到,这是一种构建自适应界面的强大方式,尤其是在百奥名哪儿些约束必须满足以及系统可以改变这些约束的相对次序时。
约束定义一个视图中的属性如何关联到另一个视图中的属性。属性是描述视图几何结构的方式,几何结构包括以下内容:
- 视图的leading边缘好trailing边缘
- 视图的left、right、top、bottom边缘
- 视图的width和height
- centerX和centerY,表示视图的X和Y中心
视图的极限。
以下是约束方程的常见形式:
view1.attribute == (view2.attribute * scaleFactor) + offset
view1.attribute和view2.attribute是两个视图及其属性,scaleFactor是第二个值要使用的比例,而offset是加到关系上的一个常数。例如,上面的关系1有两个约束。第一个约束指定视图的高度。假设高度是102点,这是约束方程:
addCarView.height == 102.0
请注意,在这个关系中并不需要其他试图,因此比例因子的有效值是0
使用比例因子的一个示例是倍增视图的宽度:
someView.width == someView.width * 2.0
在本例中,偏移量为0
最后,关系必必相等。也可以是以下情况之一:
- 小于或等于
大于或等于
例如,如果想为Car Info标签设置最小高度,可以用下面伪代码表示:
carInfoLabel.height >= MinimumHeightForContent
这个公式是一种理解如何指定约束的方法。尽管可以执行方法调用使整个公式中的所有元素创建约束,但这是最难以实现的办法。
创建约束
我们现在已经知道约束是什么了,可以用一下三种方式创建它们:
- 使用IB(Interface Builder,用户界面生成器)
- 使用VCL(Visual Constant Language,可视化约束语言)
指定关系方程中的所有部分
用IB创建约束所需做的工作最少,VCL需要做更多的工作,而定义关系方程式则需要做最多的工作。甚至可以让IB自动创建布局所需要的最少约束,但是你很可能需要修改。接下来我们将介绍如何使用IB创建约束
使用IB创建约束
了解IB中如何创建约束的最好方法是自己添加一些视图。为此,在Xcode中创建新的名为LayoutTest的单视图应用程序。介绍个组合件Cmd+Shift+N
首先将Use Auto Layout取消掉,然后添加Label到图中位置,注意我们现在用的是iPhone7
运行如图:
iPhone7 | iPhone5 |
| |
颜色都是白的就不要在意这些细节了…我想说的是用iPhone 5运行的时候,Label竟然不见了。不过我们要说服自己其实Label是在的,现在我们使用IB将顶部坐标修改为488.这时候在运行的话就能看到Label了。
change | after |
| |
像素保真帮助(Pixel-Perfect Help)
故事面板被设置为使用自动布局呢,会变得怎么样?Xcode只是在做我们要求它做的事情而已。通过将标签按照指定的宽度和高度放在指定位置,告诉Xcode那就是你想将UI元素的放置到的位置。设备有多大或屏幕处于哪个方向并不重要了。
为确保元素显示出来的效果正是我们所想要的,编译器会生成适当的约束。当开始添加自己的约束时,这些约束会优先。也就是说,编译器不会产生任何占位符约束以覆盖我们的约束。
我们可能认为这是没有帮助的,但实际上它就是我们所想要的效果。知道在我们制定其他位置之前,确保元素是像素完美的,这样就可以快速地为布局创建原型并轻易尝试约束的组合。
要理解这一点,需要添加标签与其容器底部之间距离的约束。为此,可以选择标签,(然后选择Editor|Pin|Bottom Space to Superivew 这是对于Xcode7之前的版本的,博主的版本没有,怎么办呢,看下图)
先选中1,点击2就会出现了
然后做如下修改:
记得点击Add 2 Constraints
然后运行之后,变成下面的样子了
change | after |
| |
添加两个约束练练手
示例1:
添加一个UILabel扔到屏幕上并命名为Center Y
修改如图:
你会发现,效果变成下面的样子
我们再添加一个标签Top Label
约束如图
注意圆圈部分点开三角形,选中Use Standard Value,然后点击添加
改变约束值
使用工具栏约束弹出窗口(就是上面我们用的那个窗口)是添加约束和任何常数(如距离容器或视图之间的标准距离)的很好办法。但是当前需要改变这些值时会发生什么?
一种方法是选中这个视图并打开Size检查器,这可以通过选择Center Y进行尝试。Size检查器向你显示所有相互关联的约束列表。在每个约束的右侧是一个edit,他可以让我们编辑。
例如下图
可以自己尝试的更改一下看看发生了什么变化。然后在旋转一下看看是不是管用。
除了编辑约束,还可以使用细节来验证约束确实对当前屏幕和旋转方向提供了正确的元素定位。视图之间的距离以及边缘排列还可以使用Option键来显示。Option使用方法,点击你想看的标签,选中后按下option按钮,就能显示了。
这是因为Option键可以显示当前鼠标指引下的视图与被选中的视图之间的距离。
拖拽出约束
在IB中指定约束的最后一种方法是按住Ctrl键从驶入拖动(或用鼠标右键拖动)。当结束拖动时,会跳出一个窗口。看图说的清楚一些
我先让Label与Center Y有个Top约束,所以Top前面会有白点。其余情况与之类似。这就是跳出的窗口。
今天的介绍就到这里咯
我的另一个博客站点:Arnold-你们好啊