zhengrenzhe's blog   About

理解iOS的autolayout

最近在写一个iOS的APP,应用采用了autolayout布局方式,不得不说这种布局方式真的很爽,在iOS设备尺寸越来越多样化的情况下,autolayout可以做到基本布局不用写一行代码,仅靠拖动即可完成适配所有设备的适配。本文主要将描述一下我在学习autolayout时的心路历程。

创建Project

在创建一个新的iOS Project(以Single View Application为例)后,打开Main.storyboard,可以看到一个大正方形方块,这并不是一个iOS设备,而是Xcode将各种设备抽象为一个正方形,在拖放控件时都在这个正方形里操作。

添加控件

假设现在我们想放一个text label到界面里,很简单,从右下角的控件列表里拖动一个到正方形框里就行了。

此时我将控件拖到了正方形的中间,可以看到有条蓝色的辅助线出现,说明label控件现在已经垂直居中。但是这只是在这个正方形中垂直居中,在应用中则不是。可以打开一个模拟器看一下。

可以看到label跑到了屏幕边缘了,并不在屏幕中间。出现这种情况的是因为那个正方形只是对iOS设备的一个抽象,他的尺寸并不是等比例放大或缩小到某种设备上,将模拟器与正方形重叠起来看,模拟器仅占了正方形的一半距离,在正方形中居中的label被原封不动的搬到了模拟器上,所以label会出现在屏幕边缘。

那改如何解决这种情况呢?

添加约束

在autolayout布局机制中,约束是核心的一环,他通过一系列规则限定了一个控件的位置,而不是通过具体的几个像素距离决定位置,这样的布局规则则可以轻松的拓展到各种设备及各种方向上。

约束有些抽象,他是一条规则,这条规则限定了一个控件在某一个方向上的位置,如果用语言描述一下,约束可以是这样:

子元素的左边到父元素的左外边距的距离为0

这样就描述了这个元素水平方向上的一条规则,这样不论何种设备,这个元素到父元素左外边距的距离总是0。那么怎么添加一条约束呢?方法很简单,对着想要添加约束的元素,按住control键,将指针拖向想要添加约束的方向。

这时可以看到一条蓝线,松开鼠标按键,会弹出一个菜单,里面有能添加的约束类型。

根据你鼠标拖动的方向不同,菜单里的内容也会有所不同。 通常,限定一个元素的位置都是通过多条约束组合完成的,因为只有一条约束很难确定一个元素的位置到底是在哪,假设你添加了一条约束,内容是限定元素左边到父元素的距离是20px,这样只是确定了水平的位置,竖直方向还是未知的,所以还需要再添加一条作用于竖直方向的约束。

编辑约束

直接通过拖动创建出的约束通常是需要再进一步编辑的,为什么这么说呢?假设你想创建如下约束:元素左边到父元素左margin的距离是50px,但是在正方形的抽象视图中,你并不能精确的知道20px在什么位置,通常就是一个大概的位置,这是添加条约束,约束创建时的数值是以你当前所在的位置为基准的,以下图为例,我添加一条向左的约束,label的位置是随机的,创建玩约束后双击这条约束,可以看到

选区的数值并不是50,而是82,82就是元素当前位置到父元素左边的距离,显然这是不对的。所以更改选区数值为50,之后按return键,约束就被修改了。不过这时方形视图上有些变化,约束的蓝线变成了橘黄,并且写了+32,出现这则说明元素的位置与根据约束的位置不符,差了32px。

出现这种情况的原因就是元素实际位置与目标位置不符,这有两种修改方案:

应用这两种解决方案的方法很简单,点击视图右下角的三角形按钮,会弹出一个对话框,有不同的解决约束问题的方案。

奇怪,刚不是说有两种修改方案吗,这明明是五个啊?其实这些解决方案是针对这个元素整体的修改方案,只是前两种是着重于约束位置与实际位置不相符的。在上面所说道的情况中,明显是要更新约束位置而不修改约束,所以点击 Update Frames,这时元素将会改变位置,橘黄色线就消失了。

编辑约束Ⅱ

有时我们不想将约束限定到具体的数值上,而是以倍数来决定,这时使用autolayout该怎么办呢?

回到之前那一步,在创建一条约束后,双击约束,在Xcode右侧工具栏的属性面板里可以看到关于这条约束的相关信息。

属性很多,但是它们组成了一条公式:

First Item = Second Item * Multiplier + Constant

这一条公式就是autolayout对于动态布局的万能法则,意思是说First Item 对应的值等于Second Item的值乘以Multiplier加上Constant。以这条约束为例,这条公式的含义就是:这个label左边到父元素的距离等于父元素margin乘以1加上50,由于父元素的margin为0,所哟约束计算出的值就是50。

看到这里相信已经能拓展出更多情景下的约束配置了,只要调整不同的参数,约束就会不同。假设我们想让这个元素的leading为父元素宽度的30%,那很简单,只要调整为如下配置即可:

这里的Second Item为Superview.Center X Within Margins,就是父元素宽度的一半,套用公式后可以这么理解:

Label.Leading = Super….Margins * 2 * 13 + 0

这里乘2再乘1/3的原因是Second Item是半个父元素的宽度,首先要乘以2的到整个父元素宽度,再乘以1/3。这时不论在何种设备及方向中,leading始终为父元素的1/3。

以上就是我在学习autolayout中的一点心得,其实autolayout很方便,就是上手有点困难,但是autolayout并不是万能的,更复杂的布局可能还是得通过代码形式出现。由于学习时间较短,对于autolayout的理解就暂时到这吧。

← OSX 10.11.2下Xcode7.2的GLFW, GLEW环境配置  WTF的“火星坐标” →