本文转载与 :http://blog.csdn.net/pucker/article/details/41832939
今年如约放出了新的iPhone 6与iOS 8系统,SDK针对新的设备和系统的界面适配也进行了若干改进,因此我也想借此机会跟大家分享一下我自己关于界面自动布局的理解,如有错误请不吝指教。
一、视图定位的基本原理
视图(View)是一个用于显示内容的矩形区域,它是构成app界面的最基本单元。下图为计算器app的横屏界面,其中每一个计算器按键都是一个视图。
在平面直角坐标系中,要准确描述一个矩形需要确定以下四个布局属性(Layout Attribute),即水平位置x、垂直位置y、宽度w、高度h(暂不考虑旋转)。只有上述4个布局属性都明确的情况下,该视图才能正确添加到界面中。
以上图为例,如果要将数字键5添加到界面中,则代码类似为:
- UIView* number5View = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)];
- [parentView addSubview:number5View];
上述代码详细给出了该视图的4个布局属性的值,我们姑且称这种方式为“显式坐标定位方式”。
二、旧的界面布局方式及其缺点
请思考以下问题:
- 显式坐标定位方式在处理视图数量很多时会遇到什么问题?
- 显式坐标定位方式在处理横竖屏旋转时会遇到什么问题?
首先,当视图数量很多的情况下,由于每个视图都需要明确给出4个属性,因此构建每一个视图非常繁琐而又容易出错。而且,当发生界面变化(例如横竖屏旋转)时,你需要重新计算每个视图的新的布局属性值。这显然不是一个令人满意的解决方法。
于是苹果给出了一个更好的解决方法,就是在创建视图的同时给出其相对于父视图的“对齐方式与缩放系数”,即autoresizingMask。当父视图发生变化时,通过每个子视图的autoresizingMask即可自动得出新的位置,而无需开发者提供。例如上图中的等号键,即可以指定其对齐方式为右对齐、下对齐,指定其缩放系数为固定宽度、固定高度。这样就保证了等号键总位于其父视图的右下角且宽高不变。
苹果解决问题的角度是正确的,通过给出界面变化的规则来自动计算出布局属性的值,从而省去开发者的工作。
然而autoresizingMask的问题在于:
- 其描述界面变化规则不够灵活,很多变化规则根本无法精确描述。autoresizingMask缩放比例是UIKit内部计算的,开发者无法指定缩放比例的精确值。
- 变化规则只能基于父视图与子视图之间,无法建立同级视图或者跨级视图之间的关系。例如,对于上图的计算器,autoresizingMask无法描述数字键5紧贴在数字键8下面,以及数字键0左侧与数字键1左侧对齐且数字键0右侧与数字键2右侧对齐这样的规则。
因此在过去,很多时候开发者还不得不硬着头皮使用显式坐标定位方式来解决转屏(例如重写layoutSubviews方法),或者分别做横屏与竖屏两套界面。
这些开发者都能忍,然而噩梦才刚刚开始。。。
iPhone 4s及早期的iPhone屏幕尺寸都是320*480,基本上在测试机上运行的效果就是用户运行的效果。但此后iPhone 5带来了的是16:9的宽屏,尺寸变成了320*568,另外有的app还需要同时支持iPad。难道所有这些设备都需要开发者去自己处理每个视图的精确位置,自己去处理转屏吗?
苹果也意识到了这样的问题,因此在iOS 6发布的时候引入了自动布局(Auto Layout)与布局约束(Layout Constraint)的概念,来解决上面遇到的问题。
三、自动布局的原理与使用方法
自动布局是对autoresizingMask的进一步改进,它允许开发者在界面上的任意两个视图之间建立精确的线性变化规则。所谓线性变化就是数学中的一次函数,即:
y = m*x + c
其中x和y是界面中任意两个视图的某个布局属性,m为比例系数,c为常量。例如,如果我们想描述数字键5紧贴在数字键8下方,我们可以建立如下规则:
- 数字键5的水平中心x坐标 = 1.0 * 数字键8的水平中心x坐标 + 0.0 //8和5水平中心对齐
- 数字键5的顶部y坐标 = 1.0 * 数字键8的底部y坐标 + 0.0 //8的底部为5的顶部
- 数字键5的宽度w = 1.0 * 数字键8的宽度w + 0.0 //8和5宽度相等
- 数字键5的高度h = 1.0 * 数字键8的高度h + 0.0 //8和5高度相等
每个线性变化规则称之为布局约束(Layout Constraint)。由于每个视图需要确定4个布局属性才能准确定位,因此一般来说都需要建立4个布局约束。