引言
iPhone5使屏幕从3.5"增大到了4.0",与之对应的iOS6也就引入了auto layout,auto layout是一个很重要的概念,是独立于xib的,但是auto layout从一开始就是与xib强绑定的,因为在xib里设置auto layout是最简单的。
我们这里默认大家对auto layout有基本的了解,网上有好多专门讲auto layout的教程,而且大多都是基于xib的,大家可以看看。这里 只说xib中如何设置auto layout,及其几个细节。
在xib中使用auto layout
与auto layout相关的东西几乎都在右下角的几个图标中,下面一一介绍一下:
第一个图标:
这是xcode7在iOS9中新加入的功能——stack view,相当于一个容器view用来统一管理他所有subView的约束,其实普通的UIView也可以作为容器view来管理其subView的约束,我们之前做复杂UI显示逻辑的时候往往也会放一个背景的容器view,stack view就是起到这个作用,意义不是很大,它做的事情UIView也可以做,但是他的优势在于:可以通过设置属性的方式让系统自动添加对其subView的约束,而且该view是不渲染在页面上的,对它设置背景色等属性是无效的,iOS9中与xib相关的新特性在一天一点xib:9结束语中有介绍。
第二个图标:
用于添加多个控件间对齐关系,从上到下依次是左对齐、右对齐、上对齐、下对齐、水平对齐、竖直对齐,这些现在都是灰色的不能选择,只有同时选中多个控件,他们才是可用的,或者先选择一个控件,然后按住control拖动到另一个控件上,就会弹出一个控件对齐的窗口,可以在里面设置两个控件的对齐关系。下面两个是相对于superView设置水平、竖直居中,选中单个控件就可以设置
第三个图标:
用于对单个控件设置约束,上面的四个框分别填写上下左右的约束,注意,每个框右侧的三角是可以点击出菜单进行选择的,比如有A、B、C三个控件,A、B同在C的左侧,对C设置左侧约束的时是可以选择针对A还是B进行计算的,如果通过auto layout设置的约束与显示的结果不符的时候,可以点击三角检查是不是设置约束的参照对象选错了。
Constrain to margins选项的解释:
当拖动一个控件到另一个控件里时,作为super的控件会有几条参考线(蓝色虚线,如果你使用的硬件是带有Force Touch触控板,且使用的xcode7的时候,拖动到参考线处的时候触控板会轻微震动,发出机械上的一个声音以给你反馈),上下左右四个方向的边缘会有,水平、竖直的中心处会有。
若勾选Constrain to margins实际super与sub之间的参考边缘就是这些参考线,而不是实际的super的frame的边缘,如果我们不勾选的话就是以frame的边缘为参考。
下面的Width、Height是限制自身宽高的选项。
Equal Widths、Equal Heights是与其他控件保持相同的宽高,默认是灰色不可用状态,只有选择两个以上的控件,才可使设置,同样也可以先选中一个控件,按住control拖动,弹出的窗口中也有该选项。Aspect Ratio 是设置自身的宽高比的。
Align选项同样是设置两个以上控件的对齐关系的。
Update Frames一般是用来更新frame的。我们设置的约束如果与当前控件的frame产生冲突的时候就要解决冲突,要么修改约束,要么修改frame,最后使系统可以没有歧义的确定UI布局,有冲突的时候会在xib左边栏的右上角显示警告或错误的标识,我们点击标识,按照系统提供的冲突解决方法就可以解决冲突。
第四个图标:
该图标就是为了解决冲突而产生的,以更新frame,添加约束、删除约束等等方式去解决frame与约束间的冲突。
当你设置约束发生错误,或者不知道怎么设置的时候Clear Constraints会清除所有约束,让你重新设置。
约束的设置:
约束在xib文件中表示为蓝色实线段,在xib左边栏的Constants里,当我们点击Constants里的每一项,或直接选中蓝色线段的时候,打开右边栏第五个标签——属性标签的时候就可以在里面设置参数。主要设置的就是Relation(=、>=、<=)、Constant(可以理解成偏移量)。Priority是设置约束的优先级,当我们设置了多个可以确定UI布局的约束的时候,就会用优先级高的约束去确定UI布局。
对auto layout的一些说明
很多人在刚刚学习auto layout的时候总是设置不好约束,主要原因是没有对其深刻的理解。
frame和auto layout是两种不同的布局方式,auto layout很像Android里的Relative Layout的布局样式,Android做的更纯粹。说回来,无论哪种布局样式,最终的目都是唯一、没有歧义的标识一个UI控件(包括位置和大小),道理和我们高中学过的笛卡尔坐标系(即直角坐标系用P(x,y)表示平面上的点)与极坐标系(用P(ρ,θ)表示平面上的点)是一样的,两个坐标系用不同的参数去唯一、没有歧义的表示一个点。
我们学习auto layout核心点就有两个:
1.学会用约束(约束相当于极坐标系中的参数)的思想去唯一、没有歧义的设置UI布局。
2.记住约束的公式:view1.attr1 relation view2.attr2 x multiplier + constant
relation、multiplier、constant都是可以设置的。
很多人在刚刚学习auto layout的时候总是很困惑,为什么代码修改frame不生效,下面详细的说明一下原因:
不使用auto layout时是可以在viewDidLoad:里设置frame的,一旦开启了auto layout,就要注意,通常在viewDidLoad:中设置frame就不再生效,因为iOS5加入的viewWillLayoutSubviews会在viewDidLoad之后调用,而该函数会在执行的时候去加载该文件对应的xib设置的约束,就是说在viewDidLoad:中设置frame的时机太早了,没有生效就又改成了xib中的样子,而且在viewWillLayoutSubviews中修改frame也是不生效的,那么,如何才能用代码修改布局生效?
方法一:
在viewDidLayoutSubviews中修改frame,这是最简单的方法。
方法二:
选中xib中的约束(蓝色线段,左边栏Constants里的item)像拖动其他控件一样,将其拖动成为IBOutlet的属性或全局变量,eg:
property (weak, nonatomic) IBOutlet NSLayoutConstraint *testViewWidthConstraint;
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
//通过修改约束达到修改布局的效果
self.testViewWidthConstraint.constant = 200;
}
方法二中这种修改约束constant属性的方法还可以产生动画效果,eg:
[UIView animateWithDuration:1 animations:^{
self.testViewWidthConstraint.constant = 200;
[self.view layoutIfNeeded]; //这句话很重要,只有重新布局才会产生动画效果,否则没有动画效果
}];
代码与xib设置约束的优缺点分析:
根据auto layout的公式(简单表示成a = b x c + d)可以看出用代码添加一个约束至少要指定五个参数(公式中黑体),十分麻烦,如果约束添加多了,就自然成了胶水代码,网上虽然有很多开源的auto layout的库,但最大的意义不过是对iOS系统api的封装,使其更好用了罢了,并不能从本质上解决他的复杂性的问题。
xib只需点一个按钮就能添加一个约束,十分方便,而且可视化,很容易把握整体布局中约束的设置,而且有错误和警告都有提示,修改冲突也非常容易,非要说有什么不好的地方,如果你对xib运用不熟练,看到那么多的约束都表现在xib上会有一些混乱的感觉。
总结
现在iPhone已经有四个分辨率了,可有些人写代码的时候还是用最早的方式去写——用代码去创建对象,并进行绝对布局,我只想说auto layout是布局的方向,是大势所趋,不可阻挡的,就像xib一样。
欢迎大家和我交流沟通,若文章中有错误和纰漏,恳请指正,谢谢。