自动布局-Constraint

springs和struts的问题html

你确定很熟悉autosizing masks-也被认为是springs&struts模式。autosizing mask决定了当一个视图的父视图大小改变时,其自身须要作出什么改变。它有一个灵活的或固定不变的margins(struts)吗?它的宽和高要作出什么改变(springs)?ios

 

举个例子,一个宽度灵活的视图,若是其父视图变宽,那么它也会相应的变宽。一个视图右边拥有固定的margin,那么它的右边缘将会一直粘住其父视图的右边缘。程序员

 

autosizing系统在简单的状况下很是奏效,但当你布局变得更复杂时,它立马跪了。让咱们看一个springs和struts不能处理的示例。spring

 

打开Xcode5,建立一个基于Single View Application模板的iPhone项目。叫作"StrutsProblem":编程

点击Main.storyboard。在你作别的以前,首先将这个storyboard的自动布局关了。你须要在File inspector,第一个选项的第六个tabs里:安全

 

将Use Autolayout的box勾选去掉。如今storyboard使用旧的struts-and-springs模型。app

 

注意:任何你使用Xcode4.5或更高版本中,nib或者storyboard文件都默认激活了自动布局。由于自动布局是iOS6以及以上系统的一个新特性,若是你想使用最新的Xcode开发兼容iOS5的程序,你须要将这个选项去掉。框架

 

拖拽三个新的视图到主视图上,而且像这样排列起来:iphone

为了表述更清楚,这里给出每一个视图的颜色,这样你就能分清哪一个是驴子哪一个是马了。ide

每一个视图的inset到窗口的距离都是20点;视图之间的距离也是20点。底部的视图的宽是280点,上面两个视图的宽都是130点。全部的视图的高都是254。

 

 

在iPhone Retina 4-inch simulator上运行这个程序,而且将模拟器旋转到landscape。程序看起来便变成这副鬼样,这不是我想象的那样:

注意:你可使用Hardware\Rotate Left和Rotate Right菜单选项旋转模拟器,或者经过按下键盘上的? 键,同时按下←或→。

 

而你想象的程序在landscape应该像这样:

 

很明显,三个视图的autosizing masks留下了一些须要改进的地方。将左上方视图的autosizing设置改为这样:

这将会让视图贴附左上边缘(不是右下边缘),而且当父视图大小改变时,从新调整自身水平和垂直方向的大小。

 

一样的,右上方视图的autosizing设置改为这样:

底部视图:

再次运行程序,而且旋转到landscape。如今看起来像这样:

已经很接近了,但又不彻底同样。视图之间的padding不正确。换个说法就是视图的大小不彻底正确。问题出在当父视图改变大小时,autosizing masks告诉子视图调整大小,但又没告诉子视图该调整多少(坑儿?)。

 

你能够调戏autosizing masks-好比,改变灵活宽度和高度设置(springs)-你不会获得彻底正确的三个间距20点的视图。

    

为了解决这个springs和struts方法的布局问题,很是不幸,你须要额外写一些代码。

 

在旋转用户界面以前、之间、以后,UIKit会发送一些消息到你的视图控制器,你能够截获这些消息,从而对你UI作出改变。表明性的像viewWillLayoutSubviews,你会重写这个方法从而改变任何须要从新排列的视图的frame。

 

在这以前,你须要先作出一个outlet属性来引用这个视图。

 

切换到Assistant Editor模式,按住Ctrl,将三个视图都拖到ViewController.m中去:

 

分别连接视图到这三个属性:

 
  1. @property (weak, nonatomic) IBOutlet UIView *topLeftView; 
  2. @property (weak, nonatomic) IBOutlet UIView *topRightView; 
  3. @property (weak, nonatomic) IBOutlet UIView *bottomView; 

 

下面的代码写到ViewController.m:

 
  1. - (void)viewWillLayoutSubviews 
  2.     if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) 
  3.     { 
  4.         CGRect rect = self.topLeftView.frame; 
  5.         rect.size.width = 254; 
  6.         rect.size.height = 130; 
  7.         self.topLeftView.frame = rect; 
  8.   
  9.         rect = self.topRightView.frame; 
  10.         rect.origin.x = 294; 
  11.         rect.size.width = 254; 
  12.         rect.size.height = 130; 
  13.         self.topRightView.frame = rect; 
  14.   
  15.         rect = self.bottomView.frame; 
  16.         rect.origin.y = 170; 
  17.         rect.size.width = 528; 
  18.         rect.size.height = 130; 
  19.         self.bottomView.frame = rect; 
  20.     } 
  21.     else 
  22.     { 
  23.         CGRect rect = self.topLeftView.frame; 
  24.         rect.size.width = 130; 
  25.         rect.size.height = 254; 
  26.         self.topLeftView.frame = rect; 
  27.   
  28.         rect = self.topRightView.frame; 
  29.         rect.origin.x = 170; 
  30.         rect.size.width = 130; 
  31.         rect.size.height = 254; 
  32.         self.topRightView.frame = rect; 
  33.   
  34.         rect = self.bottomView.frame; 
  35.         rect.origin.y = 295; 
  36.         rect.size.width = 280; 
  37.         rect.size.height = 254; 
  38.         self.bottomView.frame = rect; 
  39.     } 

当视图控制器旋转到一个新的方向,这个回调将会被调用。它会监控视图控制器旋转的方向,而且适当的调整视图大小-在这种状况,根据已知iPhone屏幕大小会有一个hard-code(将可变变量用一个固定值来代替的方法叫作hard-code)偏移。这个回调会在一个动画block中发生,因此会动态的改变大小。

 

暂时还不要运行这个程序。首先你须要按下面的样子从新保存三个视图的autosizing masks,不然autosizing mechanism将会和你在viewWillLayoutSubviews中设置的位置和大小冲突。

这样就能够了,运行程序而且翻转到landscape。如今视图排列的很是号。翻转回到portrait,经核实,一切都良好。

 

这样奏效了,可是你须要为这个很是简单的例子编写大量的布局代码。想象一下,为布局付出的努力是很是复杂的,特别是个别视图动态的改变大小,或者子视图的个数是不固定的。

 

如今试着在3.5寸的模拟器上运行程序。我了个去。视图的位置和大小又错了,由于viewWillLayoutSubviews的hard-code坐标是基于4英寸大小的手机(320x568取代320x480)。你能够增长另外一个if语句判断屏幕大小,并使用不一样的坐标集,可是你能够看到这个方法很快变得不切实际。

注意:另外一个你能够采起的方法就是为portrait和landscape模式创建独立的nibs。当设备旋转时,你从另外一个nib中装载视图并替换掉当前的那个。但这任然须要作不少工做,而且维护两个nibs也会增长问题。当你使用storyboards替代nibs的时候,这个方法也变得不切实际。

 

自动布局拯救猿!

如今你将会看到如何用自动布局实现相同的效果,从ViewController.m中移除viewWillLayoutSubviews,由于咱们再也不须要写任何代码。

 

选择Main.storyboard,并在File inspector中选择开启Use Autolayout:

运行程序,旋转到landscape。如今看起来像这样:

让咱们把自动布局付诸行动。当你点击顶部两个视图时,按住?键,这样两个视图都被选中了。从Xcode的Editor菜单中选择Pin\Widths Equally:

再次选中两个相同的视图,选择Editor\Pin\Horizontal Spacing。(尽管你执行完第一次Pin处理后,两个视图看起来仍是被选中的,但其实他们只是在一个特别的布局关系显示模型里。因此你须要从新选择这两个视图)

 

storyboard如今看起来像这样:

橙色的"T-bar"形状表明视图间的约束。目前为止你增长了两个约束:一个等宽约束和一个位于两个视图间的水平约束。约束表达了视图之间的关系,而且他们是你使用自动布局创建布局最主要的工具。这货看起来有点吓人,可是一旦弄懂它的意思,便变得至关简单。

 

为了继续为这个屏幕简历布局,执行下面这些步骤。每一个步骤增长更多橘黄色的T-bars.

 

o Top Space to Superview

o Leading Space to Superview

For the view on the right, choose:

o Top Space to Superview

o Trailing Space to Superview

And for the big view at the bottom:

o Leading Space to Superview

o Trailing Space to Superview

o Bottom Space to Superview

 

如今你应该有了下面这些约束:

注意T-bars仍然是橘黄色的。这意味这你的布局没有完成;自动布局没有足够的约束条件计算出视图的位置和大小。解决办法即是增长更多约束,直到他们变蓝。

 

按下? 键并选中三个视图。从Editor菜单中,选择Pin\Heights Equally。

 

如今选中左上角的视图和底部视图(像前面同样按住? 键),选择Editor\Pin\Vertical Spacing.

 

Interface Builder看起来应该像这样:

T-bars已经变蓝了。自动布局如今已经有足够的信息来计算出一个有效的布局。这看起来有点杂乱无章,这是由于等宽和等高约束条件占去了很大空间。

 

运行程序而且...我说吧,不须要写一行代码便运行的很好了。无论你在哪一个模拟器上运行;在3.5英寸和4英寸设备上,布局都运行良好。

这很是酷,可是究竟你在这作了什么?自动布局让你表达出布局中的视图和其余每一个视图的关系,而不是须要你指出视图有多大,放在哪儿。你须要放置如下这些关系(即咱们所谓的约束)到布局中:

1.左上角和右上角的视图老是有相等的宽度(也就是pin中第一个widths equally命令)。

2.左上角和右上角的视图水平方向有20点距离(也就是pin中的horizontal spacing)。

3.全部的视图老是有相同的高度(也就是pin中heights equally命令)。

4.上面两个视图和下面那个视图垂直方向上有20点距离(也就是pin中的vertical spacing)。

5.视图和屏幕边缘有20点空间(top,bottom,leading和trailing space相对于父视图的约束)。

 

这些就足以表达出自动布局该怎么放置视图,以及当屏幕大小改变时该如何处理。

你能够在左边Document Outline中看到你全部的约束,组名叫作Constraints(当你为storyboard激活自动布局时才会加进来)。

 

若是你在Document Outline中点击一个约束,Interface Builder将会在视图中高亮出它:

 

约束是一个真实的对象(NSLayoutConstraint),而且他们也有属性。好比,选择上面两个视图的间距约束条件(叫作"Horizontal Space(20)"),而后切换到Attributes inspector。你能够在那里经过编辑Constant字段改变边缘空间的大小。

将它设置为100,而后再次运行程序。如今他们边缘空间变得更宽了:

自动布局在描述视图上比springs和struts显得更有表现力。在这篇教程的剩余部分,你将会学到约束的一切,以及如何将他们应用到Interface Builder上来构造出不一样种类的布局。

 

自动布局如何工做

正如你在上面测试样例中所看到的同样,自动布局最基本的工具是约束。一个约束描述了两个视图间的几何关系。好比,你可能有这样一个约束:

"label A右边缘和button B左边缘有20点的空白空间。"

 

自动布局会考虑到全部的约束,而后为你的视图计算出理想的位置和大小。你不再须要亲自为你的视图设置frames了-自动布局会彻底基于你为这些视图设置的约束为你作这个工做。

 

自动布局之前,你一直须要为视图的frames设置hard-code,要么在Interface Builder中将他们放置在特定的坐标,或经过传递一个rectangle到initWithFrame:,或者设置视图的frame,bounds或者center属性。

 

就你刚刚作的那个程序,你须要明确设置frames为:

还须要为这些视图设置自动调整大小的masks:

 

这不再是你须要为屏幕设计所考虑的东西了。使用自动布局,你须要作这些:

视图的大小和位置不再重要了,只有约束要紧。固然,当你拖一个新建的button或label到画布上时,它会有必定的大小,而且你会将它拖到某一位置,但这是只一个用来告诉Interface Builder如何放置约束的设计工具。

 

 

想你所想,如你所愿

使用约束最大的优点就是你不再须要把时间浪费在坐标上了。相反,你能够向自动布局描述视图如何和其余视图相关联,自动布局将会为你完成全部困难的工做。这叫作根据目的设计(designing by intent)。

 

当你根据目的设计时,你表达的是你想要实现什么,而不须要关心它如何实现。"button的左上角坐标为(20,230)",如今你能够这么说了:button是垂直居中于它的父视图,而且相对于父视图的左边缘有一个固定的距离。

 

使用这个描述,无论父视图多大或多小,自动布局均可以自动计算出你的button须要在哪儿出现,

 

其余根据目的设计的示例(自动布局能够处理全部这些指令):

"这两个text fields的大小须要一直相等。"

"这两个button须要一直一块儿移动。"

"这四个labels须要一直右对齐。"

 

这使得你用户界面的设置更具描述性。你只需简单的定义约束,系统会为你自动计算frames。

 

在第一部分你看到,即便为几个视图在横竖方向上正确的布局都须要作大量的工做。有了自动布局,你能够绕过这些麻烦。若是你正确的设置了约束,那么在横竖屏方向上,布局将不须要作任何改变。

 

使用自动布局另外一个重要的好处就是本地化。好比德语中的文本,出了名的比老奶奶的裹脚布还要长,适配起来是一件很麻烦的事。再次,自动布局拯救了猿,由于它能根据label须要显示的内容自动改变label的大小。

 

如今增长德语,法语或者其余任何一种语言,都只是设置约束的事,而后翻译文本,而后。。。就没有而后了!

得到自动布局窍门最好的方法就是使用它,因此这正是剩下教程中你会学到的东西。

 

注意:自动布局不只对旋转有做用;它还能轻易的缩放你UI的大小从而适应不一样尺寸的屏幕。这并非巧合,当iPhone5拥有更高屏幕的同时,这个技术也同时加到了iOS中!自动布局能轻易的拉伸你程序的用户界面,从而充满iPhone5垂直方向上多出来的空间。随着iOS7中的动态类型,自动布局变得更加剧要了。用户如今能够改变全局字体大小设置--有了自动布局,这将变得很是简单。

 

 

拥抱约束(courting constraints)

关闭你当前的项目并用Single View Application模板建立一个新的iPhone项目。叫作"Constraints"。任何用Xcode5建立出来的项目都会自动假定你会使用自动布局,因此你并不须要额外作任何事情。

 

点击Main.storyboard打开Interface Builder。拖一个新的Button到画布上。注意当你拖拽的时候,蓝色虚线将会出现。这写线用来作向导。

在屏幕边缘以及中心的时候,都会有向导线:

 

若是以前你已经使用过Interface Builder,那么你确定看到过这些向导线。这对咱们对齐控件有很大的帮助。

 

在Xcode4中激活自动布局时,向导线有另一个目的。你任然能够用他们来对齐,可是他们也会告诉你新的约束将会在哪儿。若是你将button沿着向导线反方向拖拽到左上角时,Xcode4中的storyboard看起来便像这样:

有两个蓝色的东西附属在button上面。这些T-bar形状的对象即是约束了。Xcode 4的Interface Builder中无论你将UI控制器放在哪儿,它老是会给出有效的约束。理论上这听起来是个好主意,可是实践起来,在Interface Builder中使用自动布局却很是困难。

 

幸运的是,Xcode5中已经有所好转。将button拖拽到画布上以后并看不到T-bars形状的东西:

 

同时在Document Outline面板中也没用Constraints部分。获得结论:此时button上并无设置任何约束。

 

那这是如何运做的呢?咱们以前了解的自动布局老是须要足够多的约束才能决定视图的大小和位置,可是如今咱们这儿跟本没有约束。肯定这是一个完整的布局?

 

这这是Xcode5相对Xcode4来讲最大的一个提高:不再强制你老是有一个有效的布局。

 

注意:1.运行一个无效布局的程序是不明智的,由于自动布局不能正确的计算须要将视图放在哪儿。要么视图的位置是不可预知的(约束不够),要么程序将会崩溃(约束过多)。

 

2.Xcode4设法保证老是有足够多正确的约束来建立一个有效的布局。不幸的是,它常常会将你的约束替换为你并不想要的。这会使人很沮丧,正是由于这个缘由不少开发者放弃了自动布局。

 

3.Xcode5中,当你编辑Storyboard时它容许你有不完整的布局,但它也会指出哪些地方你还须要修改。使用Interface Builder建立的自动布局驱动用户界面变得更有趣了,使用Xcode5也消耗更少的时间。

 

若是你根本不提供任何约束,Xcode自动分配一套默认的约束,正是咱们所知的自动约束。它会在程序built的编译时间中去完成这些事,而不是设计时间。当你设计你的用户界面时,Xcode5中的自动布局为了避免参与你的设计方法而努力工做,这这是咱们喜欢它的缘由。

 

自动约束为你的视图提供一个固定尺寸和位置。换句话说,视图老是拥有跟你在storyboard中看到的同样的坐标。这是很是方便的,由于这就意味着你能够大量的忽视自动布局。你能够为那些拥有充分约束的控件不增长约束,只为那些须要特殊规则的视图建立约束。

 

OK,让咱们玩一玩约束并看看他们能作什么。如今,按钮是在左上角,而且没有约束。确认按钮跟两个拐角向导线对齐。

 

使用Editor\Pin菜单为按钮增长两个新的约束,看起来像这样:

这是Leading Space to Superview和Top Space to Superview选项。

 

全部的约束都会在Document Outline面板中列出来:

目前有两个约束,一个是button和main view左边缘的Horizontal Space约束,一个是button和main view上边缘的Vertical Space约束。这个关系经过约束描述起来即是:"button老是位于其父视图左上角20点处。"

 

注意:这些其实都不是很是有用的约束,由于他们有相同的自动约束。若是你老是想你的button相对于父视图左上角,那么你还不如不提供任何约束,让Xcode为你作这些。

 

如今拖动button并将它放到屏幕的右上角,再次和蓝色向导线对齐:

哇哦,这里发生了什么?在Xcode4中这会破坏旧的约束并赋值一个基于蓝色向导线的新约束,可是在Xcode5中button保留了现存的约束。但问题是button在Interface Builder中的大小和位置不再和自动布局但愿基于约束的大小和位置相符合了。这叫作错位的视图。(misplaced view)

 

运行程序。Button仍然会出如今屏幕的左上角:

 

当谈到自动布局,橙色表明坏的。Interface Builder绘制两个橙色方块:一个是虚线边框,一个是实线边框。虚线方块是根据自动布局显示视图的frame。实线方块是根据你在屏幕上放置的视图的frame。这两个应该吻合的,可是这里并无。

 

如何修改取决于你想要达到什么目的:

1.你想让button附属于屏幕左边缘254点处吗?在这种状况下你须要将现存的Horizontal Space约束变大234点。这正是橙色badge中"+234"的意思。

2.你想让button附属于屏幕的右边缘?那么你须要移除现有的约束并从新建立一个新的。

 

删除Horizontal Space约束。首先在画布或Document Outline中选中,而后按键盘上的Delete键。

注意此次Vertical Space约束变橙色了。直到如今它都是蓝色的。那一个约束并无任何错误;它的意思是剩下的没有足够的约束决定button完整的位置。你任然须要在X轴方向增长一个约束。

 

Note:你可能会奇怪,为何Xcode不为X轴方向自动增长一个约束。Xcode中的规则是:Xcode只为那些你没有设置任何约束的对象建立自动约束。一旦你增长一个约束,你即是告诉Xcode你接管了这个视图。Xcode将再也不增长任何自动约束,并但愿你为这个视图增长须要的约束。

 

选中button,并选择Editor\Pin|Trailing Space to Superview.这迫使在button右边缘和屏幕右边缘增长一个新的约束。关系表达以下:"button老是位于距离其父视图右上角20点处。"

 

运行程序并旋转到landscape。注意button如何与屏幕右边缘保持相同距离:

 

当你放置一个对立于向导线的button(或者任何其余视图)并新建一个约束时,你会获得一个根据"HIG"(Apple's iOS Human Interface Guidelines document)定义的标准大小的间隔约束。对于边框来讲,标准大小空间是20点。

 

如今将button向左拖拽一点:

因为视图错位,你获得了一个橙色虚线边框。咱们假设这个button新位置的确是你想要的。建立完一个约束后作一些细微的调整是很常见的,但这却会致使橙色方块出现。一个修改方法就是移除约束并建立一个新的,但还有一个更简单的解决方案。

 

Editor菜单上有一个Resolve Auto Layout Issues子菜单。从这个菜单中,选中Update Constraints。就我这个状况来讲,这会告诉Interface Builder须要将约束变大64点,像这样:

 

很好,T-bars又变蓝了,布局是有效的。在Document Outline中,你能够看到Horizontal Space约束再也不有一个标准的间隔了:

到目前为止你已经尝试过了Horizontal Space和Vertical Space约束。还有一个"center"约束。拖拽一个新的Button对象到画布底部中心,根据向导线无缺入位:

 

为了保持button在水平方向上一直居中对齐于父视图,你须要增长一个Center X Alignment约束。从Editor菜单选择Align\Horizontal Center in Container.这会增长一个很长的橙色线段:

 

 

线之因此是橙色是由于你才仅仅指定了button的X轴,但Y轴并无指定约束。使用Editor\Pin菜单在button和视图底部间增长一个Vertical Space约束。看起来像这样:

 

若是你不知道缘由,这是Bottom Space to Superview选项。Vertical Space约束使button远离视图底部(再一次使用标准间隔)。

 

运行程序并旋转到横屏模式。甚至在横屏模式,button也保持在屏幕底部的中心:

这就是你表达的意思---这个button始终应该位于底部中心。注意,你根本不须要告诉Interface Builder按钮的坐标是什么,除非你想将它固定在视图上。

 

 

经过自动布局,你不再须要担忧视图位置的精确坐标或视图大小了。相反,自动布局会根据你设置的约束获得这两个参数。

 

你能够在button的Size inspector中看到这个经典转移,如今有了很大的不一样:

 

若是不使用自动布局,输入值到X,Y,Width或Height字段将会改变选中视图的位置和大小。使用自动布局后,你仍然能够输入新值到这些字段,可是若是你已经为视图设置了约束,那这可能形成视图错位。你将不得不更新约束来匹配新值。

 

举个例子,把button的宽度改成100,画布会变成这样:

 

Xcode4用Horizontal Space取代Center X Alignment约束,而且button上会产生一个新约束强制它的宽度为100 points。然而,Xcode5说,"若是你想让button宽度变为100 points,对我来讲无所谓,可是你要知道约束并非这么说的。"

 

在这种状况下你但愿button是100点宽。对此有一个特殊的约束类型:Fixed Width约束。首先按一下Undo,这样button又居中了,T-bars也变蓝了。选中button并选择Editor\Pin\Width。这会在button下面放置一个新T-bar:

 

选中那个T-bar并在Attributes inspector中改变Constant为100.无论button的title多大或多小,这都会强制button的宽老是100点。为了能更好的看清你能够给button设置一个背景色:

 

 

你也能够在左边的Document Outline中看到这个新的Width约束:

 

与其余约束不一样,在button和它的父视图之间,Width约束只会应用到button自己。你能够将这个认为是一个button自己和自己之间的约束。

 

你可能怀疑为何button以前没有Width约束。自动布局是为什么知道button有多宽?

 

事情是这样的:button本身是知道本身有多宽。它根据本身的title text加上一些padding就好了。若是你为button设置一个背景图片,它也会考虑进去。

 

这正是咱们熟悉的intrinsic content size。并非全部的控制器都有这个,但大部分是(UILabel是一个例子)。若是一个视图能够计算本身理想的大小,那么你就不须要为它特别指定Width或Height约束了,你将会在稍后看到更多相关内容。

 

 

为了恢复button到最佳大小,首先咱们须要移除Width约束。而后选中button,并从Editor菜单中选择Size to Fit Content。这样就可以恢复button的固有的内容尺寸了。

 

孤掌难鸣

向导线不但出如今一个视图和它的父视图之间,并且也会出如今相同层级的视图之间。拖拽一个新的button到画布上进行演示。若是你将这个button拖近其余对象,这时他们的向导线将会开始相互影响。

 

将新button放到以前一个button的后面无缺入位:

 

这还有一些向导虚线。Interface Builder识别出这两个button能够经过不一样方式对齐—顶部,中心以及基线。

 

Xcode4会将这些显著的向导线转变成新的约束。可是在Xcode5中,若是你想让这两个button间有约束,你须要本身建立。以前你已经使用过Editor\Pin菜单来建立这两个视图间的约束,可是还有一个更简单的方式。

 

选中新的button并按住Ctrl拖拽到另外一个button上,像这样:

放开鼠标按键,出现一个弹出框。选择第一个选项,Horizontal Spacing。

这将会建立一个新的约束:

 

 

它是橙色的,这意味着这个button至少还须要另外一个约束。button的大小是知道的(使用intrinsic content size),而且还有一个button在X轴上的约束。只剩下Y轴没有约束了。

 

这种缺失约束的状况是很容易肯定的,可是更复杂的设计可能就没这么明显了。幸运的是,你再也不须要敏思苦想,Xcode已经记录并能够确切的告诉你缺乏了什么。

 

在Document Outline中会有一个红色的小箭头,就在View Controller Scene后面。点击这个箭头便会看到全部Auto Layout问题:

 

咱们将Y轴方向缺失的约束加进去。按住Ctrl并向下拖拽新的button:

此次弹出菜单有不一样的选项了。此次菜单的选项是基于上下文环境的—你在哪些视图间拖拽以及鼠标移动的方向。选择Bottom Space to Bottom Layout。

 

如今新button有一个位于屏幕底部的Vertical Space,也有一个跟其余button相关联的Horizontal Space。虽然空间很是小(只有8 points),T-bar可能不大容易看到,但它就在那里。

 

点击Document Outline里面的Horizontal Space(8):

 

当你选中一个约束,它会高亮本身所属的控制器。这个特别的约束位于两个button之间。这个约束表达了:“无论第一个button在哪儿或多大,第二个button老是出如今第一个button的左边”。

 

选中黄色背景的button并输入较长的label,好比:“A longer label”。输入完成后,button会为新的text改变大小,而且另外一个button会移开。

 

最终,它依附在第一个button的左边缘,这正是咱们所指望的:

 

为了更好的摸索这是如何工做的,多练一些吧。拖拽另外一个button到画布上并放到黄色button的上方,他们会垂直方向对齐到位(不要试着让两个button的左边缘对齐):

 

为新button设置一个绿色背景色,这样就能够更容易看出它的范围。

 

由于你将两个button对齐在一块儿,如今他们之间存在HIG推荐的8 points间隔。按住Ctrl在两个button之间拖拽将这变为一个约束。从弹出菜单中选中Vertical Spacing。

 

Note:“HIG”是“iOS Human Interface Guidelines”的简称,包含Apple推荐的良好的用户界面设计。任何iOS开发者都有必要读一读这个规范。HIG解释了哪些UI元素适合在什么状况下使用,以及最佳使用方式。你能够在这里找到。(https://developer.apple.com/library/ios/DOCUMENTATION/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html

 

然而你并无被限制在controls间的标准间隔。约束是成熟的对象,就像视图同样,所以你能够改变它们的属性。

 

选中两个button之间的Vertical Space约束。你能够在画布上点击T-bar,虽然这有点麻烦。目前最简单的办法就是在Document Outline里面选择约束。一旦你选中约束,再切换到Attributes inspector:

 

在Constant字段里输入40改变约束大小。如今两个button更进一步的分开了,可是他们任然是链接在一块儿的:

 

运行程序并翻转到landscape模式查看效果:

 

button必然会保持他们垂直方向的排列,可是水平方向就不了!缘由很明显:绿色button尚未X轴方向的约束。

 

为绿色button增长一个到屏幕左边缘的Horizontal Space并不能解决问题。这样的约束只会让绿色按钮老是保持在同一个X轴坐标,即使是在横屏模式下。这看起来感受不大对,因此你须要表述这样一个目的:

“黄色button会一直水平居中,蓝色button左边缘会一直跟黄色button左边缘对齐。”

 

你已经为第一种状况建立了一个约束,可是第二个并无。Interface Builder为对齐显示了向导线,这样你就能够将上面button一直拖拽到跟黄色左边缘对齐的位置:

 

若是你也在垂直方向上拖拽button,这时button框架和Vertical Space约束之间就不能达到正确的距离了。你在T-bar上将会看到橙色的badge:

若是发生这样的状况,简单的使用方向键将button微调到位,直到badge消失。

 

最终,按住Ctrl在两个button间拖拽,从弹出菜单中选择Left。这会建立一个约束:“两个视图的左边缘一直对齐”。换句话说,这两个button一直会有相同的X轴坐标。这时T-bars变成蓝色了:

 

运行程序并旋转到横屏模式:

 

何去何从?

如今你已经对自动布局进行了第一次尝试,感受怎么样?这可能须要一些时间习惯,可是它能让你的工做更加简单,也会让你的app更加灵活。

 

想要学习更多的内容?继续阅读第二部分吧,你将会继续在Interface Builder中使用button进一步理解Auto Layout提供的多种可能性,以及你可能遇到的问题。

 

最重要的是,你将会使用Auto Layout在一个真实的程序中建立一个逼真的布局。

 

 

(翻译)开始iOS 7中自动布局教程(二)

0

来源:cnblog    阅读:189   时间:2014-09-20

 

原文地址:Beginning Auto Layout Tutorial in iOS 7: Part 2

正文以下:

 

开始iOS 7中自动布局教程(一) 你已经看到旧的“struts-and-springs”模型让user interfaces不能较容易的解决全部的布局问题。自动布局是一个解决方案,可是也是由于它的强大,因此在使用它的时候,咱们须要一点小技巧。

值得高兴的是,Xcode5让自动布局更容易了。若是你在Xcode4中尝试过自动布局而且放弃了,那如今咱们但愿你能再给它一个机会。咱们将在Xcode5中使用它。

在第二部分和最后一部分自动布局的系列教程中,你将要继续学习全部关于约束的知识以及如何应用它们。

 

千里之行始于足下

这个自动布局的教程将从下面这个很是简单的app开始:

app中有两个设置了背景色的按钮,你能够更清楚的看到它们的边界。它们之间有一些约束。若是你学习的上一部分,你能够继续使用你以前的app,只要你移除界面上的其它两个按钮。

若是你打算从新开始,请使用Single View Application模板建立一个新的iPhone应用。拖两个按钮到场景中而且给它们设置背景颜色。使用Editor\Pin菜单在两个按钮之间建立一个Vertical Spacing约束,而后靠下的按钮建立一个Bottom Space to Superview约束(大小为20点)。使用Editor\Align菜单给黄色按钮建立一个横向居中的约束,而后两个按钮align the left edges(对齐左边缘)。

在Interface Builder中执行,一切看起来都很棒。可是让咱们看看它们是怎么工做的。在ViewController.m中加入下面的方法:


- (IBAction)buttonTapped:(UIButton *)sender
{
    if ([[sender titleForState:UIControlStateNormal] isEqualToString:@"X"]) {
        [sender setTitle:@"A very long title for this button" 
                forState:UIControlStateNormal];
   } else {
        [sender setTitle:@"X" forState:UIControlStateNormal];
   }
}

给长标题和短标题按钮都设置单击触发事件。在Interface Builder中将按钮都链接到action方法上。按住ctrl拖拽每一个按钮到view controller而且在弹出窗中选择buttonTapped。

运行这个app而且单击按钮,看看它是怎么变化的。能够在横屏和竖屏都进行测试。

无论按钮是长标题仍是短标题,布局老是被安全的约束着:

  • 靠下的按钮老是在视图中横向居中
  • 靠下的按钮老是距离视图底部20点
  • 靠上的按钮老是和靠下的按钮左对齐,而且它们之间的距离老是40点。

上面三点就是你的user interface中所显示的所有说明

让咱们来试试,移除左对齐约束(在outline窗口中选择而且按下Delete键),而后选中在Interface Builder里的全部按钮,在对齐菜单中选择对齐右边缘。如今再次运行你的app观察与以前的区别。

咱们再来一次,此次选择Align\Horizontal Centers。它将使两个按钮老是居中对齐。运行app,点击按钮,看看它们是怎么运行的。(记住,若是你改变约束时看到了橘黄色的虚线矩形,你可使用 Editor\Resolve Auto Layout Issuesmenu来更新按钮的大小和位置。)

处理宽度

Pin菜单有一个选项是Widths Equally。若是你在两个view中设置了这个约束,自动布局将老是让全部view的宽度等同于最大的那个view的宽度,让咱们来试试。

选中全部按钮,而且选择Editor\Pin\Widths Equally。这就给全部按钮都加上了一个新约束:

在这以前,你能够先看看教程第一部分的关于约束类型的内容。它看起来就像一个T字架,但在中间有一个写着“=”号的圆。

固然,也许是两个T字架,在Outline文档中显示了一个单独的Equal Widths约束:

改变按钮上的label文本,两个按钮的尺寸都会同时改变。将下面的按钮的label文本改成“X”。这时候,你会发现上面的按钮,不能再匹配它的文本了:

那自动布局是怎么知道使用哪一个按钮的宽度呢?若是你留心一点,你可能注意到上面的按钮的尺寸再也不正确了:

显然这不是你想要的效果,选择上面的按钮并选择Size to Fit Content从Editor菜单中(或使用快捷键 ⌘ =)。如今,文本再次匹配按钮了,而且由于Equal Widths约束的缘由,黄色按钮也改变了尺寸。

运行app而且单击按钮,这个按钮如今老是同样宽了,无论哪个label更大:

固然,若是label都很是短,按钮都会等宽收缩。除非有其余约束阻止了,不然按钮尺寸将会精确的匹配它们的标题,很少,很多。咱们怎么称呼这种状况?对的,就是固有内容大小。


固有内容大小

在有自动布局以前,你老是须要告诉按钮和其余的控件它们应该有多大,而后设置它们的frame或bounds,再或者在Interface Builder里恢复它们的尺寸。可是如今状况改变了。大多数控件彻底能够根据内容来决定它们到底须要多宽。标签能够知道本身有多宽多高,由于它知道文本的长度和文字的大小。按钮也同样,能够根据文本,背景图和内边距等来决定大小。一样的,这对于segmented controls, progress bars和其余大多数的控件也都是有效的,不过可能其中有一些控件只能预判高度而不能知道它的宽度。这种特性被叫作固有内容大小,它对于自动布局是一个很重要的概念。你已经见过button的action了。自动布局会询问你的控件须要多大,而且会依据那些信息在屏幕上把控件画出来。一般状况下,你都会使用固有内容大小,但也有一些特殊状况你不想用它。那你就能够给控件设置一个准确的Width和Height约束来阻止固有尺寸大小的使用。设想一下,你在UIImageView上设置了一张图片,若是图片的大小超出了屏幕,会发生什么?你能够给这个image view一个固定的宽高和缩放比例,除非你想重定义图片的尺寸。

 若是你给按钮一个固定宽度的约束会发生什么?按钮会计算本身的尺寸,可是若是你给了一个固定的尺寸,它就不会再计算。选择靠上的按钮而且选择Pin\Widthfrom菜单。给按钮添加一个固定宽度(在按钮下方出现一个完整的T字架):

由于这种类型的约束只会对按钮自己有效,对它的父视图无效,因此在Outline文档中,它将会列在按钮对象下面,你能够固定这个按钮的宽度为46点。

你不能简单的拉伸按钮来调整大小。若是你这么作了,你最后只会获得一个橘黄色的虚线框。必定要记住,在Xcode5中不会自动更新约束(不像Xcode4)。所以,若是你改变了按钮的尺寸和位置,他会提示你须要让约束再次匹配。这是仅简单的改变约束的一种替代方法。

选择Width约束并进入Attributes inspector选项卡。把按钮的宽度约束改成80点:

运行app并点击按钮,发生了什么?按钮的文本改变了,可是它被删除了一部分,这是由于在按钮中没有足够的空间:

由于靠上的按钮有一个fixed-width约束,而且全部的按钮都要求同样的尺寸,全部它们就永远不会收缩或者扩展。

注意:你可能在设计中不想给按钮设置Width约束,那最好的办法就是让按钮使用固有尺寸,可是若是你遇到你想在app运行时改变控件的尺寸,可是却不能的状况。你就应该仔细检查一下是否是有fixed Width尺寸约束在做祟。

Play around with this stuff for a bit to get the hang of pinning and aligning views. Get a feel for it, (这句翻译不了,自行解决~)不是一切都能马上就显而易见的,你只要记住必须有足够的约束自动布局才能预计算全部视图的位置和尺寸。

画廊例子

你如今可能会想约束究竟是什么,你要怎么样才能经过创建不一样视图之间的关系,从而构建起本身的布局。在下面一节中,你将看到怎么使用自动布局和约束来建立一个符合真实世界场景的布局。

让咱们伪装你想作一个浏览你图片的程序。它在横屏和竖屏中看起来就像下面这样:

屏幕被分红了4块,每一块都有一个image view和label。咱们要怎么样才能达到这种效果呢?

让咱们开始创做这个app吧。首先用Single View Application模板建立一个新的iphone项目,名字叫“Gallery”。

打开Main.storyboard。从Object Library中拖拽View到视图上。把尺寸设置为160点和284点,而且把它的背景色变为白色之外的其余颜色(例如:绿色):

注意:拖拽UIView到故事板上有两个缘由:a)你要使用它来包含其余的控件视图,这些控件能够帮助你组织起场景的内容;b)它也做为一个自定义view或控制器的占位符,你能够设置它的Class属性,将它变为你自定义的UIView/UIControl的类(即继承UIView/UICtontrol的类)。

让咱们给这些view一点约束。你已经看过加约束的两种方式:用Editor\Pin和Align菜单,还有按住ctrl在两个view之间拖拽。这里告诉你第三种添加约束的方法。在Interface Builder窗口的底部有一行这样的按钮: 

椭圆包围的四个按钮就是用于自动布局的。从左到右分别是:对其(Align),固定(Pin),解决自动布局问题(Resolve Auto Layout Issues)和重定义尺寸(Resizing Behavior)。前三个按钮鱼Editor菜单中的对应项有一致的功能。Resizing Behavior按钮容许你在从新设置view的尺寸的时候,改变已经添加的约束。

选择绿色的view而且点击Pin按钮。会弹出一系列你能够添加的约束:

 

顶部的Spacing to nearest neighbor是最常常用到的。点击者4个T字架,它们就会变成实体的红色:

这样就会给绿色的view和它的父视图的四边建立四个新约束。实际上的间距值因人而异,这要看你view的位置。(你不须要改变这些值来匹配个人图)。点击 Click Add 4 Constraints完成约束的添加

如今你的故事板看起来应该这样:

视图须要这4个约束来保证它的位置。UIView不像button或者label,它没有固有内容大小。你必须有足够的约束来保证每一个view的位置和尺寸,view老是须要约束来告诉它,它须要多大。

你可能会奇怪,尺寸的约束在哪?在这个案例中,view的尺寸约束是隐含在父视图的尺寸中。布局中有两个Horizontal Spaces约束和两个Vertical Spaces约束,这样就能保证固定的长度。你在Outline文档中能够看到他们:

绿色view的宽是由这个公式计算出来的:“父视图的宽-(98+62)”,它的高是:“父视图的高-(65+199)”。这样,间距就被固定了,你的view除了从新定义尺寸以外别无他法。(你的值可能会有所不一样,它依据于你的view放的位置)。

当你旋转这个app的时候,父视图的规格就会从320X568变为568X320。公式就会从新计算宽和高,这时候你会获得新的绿色view的尺寸(408X56)。

你能够旋转你本身的试试,你也能够在Interface Builder直观的模拟它们。打开Assistant editor(按Xcode工具栏中看起来像 外星人/男管家 的那个按钮)而且在弹出的菜单中选择Preview:

单击底部的箭头按钮能够改变界面的方向。这样就能马上给你一个横屏的故事板布局预览。绿色view会重定义尺寸以知足横向间距和纵向间距的约束。

你能够留下这个预览窗口,当你设计UI时,它会自动改变。你也能够在3.5吋和4吋屏之间切换。

注意:你可能会奇怪为何顶部的约束没有顶到屏幕的最上面:

而是停在了状态栏处。这是由于在ios7中,状态栏老是绘制在view控制器的顶部 - 而再也不是一个单独的bar。这样作有什么用?当你建立约束时,它没法确切的依附在屏幕顶部,可是顶部会有一个看不见的行,它叫作 Top Layout Guide。

在一个正常的view控制器中,这个guide距顶部有20点,至少在状态栏不隐藏的时候是这样的。在导航控制器中,它位于导航栏下面。由于导航栏在视图中有不同的高度, Top Layout Guide会在设备旋转时随着导航栏移动。这样就很容易的获得view和导航栏的相对位置。一样的,底部也有Bottom Layout Guide,用来放置标签栏和工具栏。

有时候,可能你不想在设备旋转时重设你的UIView的尺寸,所以你能够给这个view一个固定的宽高约束。如今,让咱们来试试。选择绿色的view并点击Pin按钮;在弹出窗口中给width和height打上勾。

点击Add 2 Constraints来完成约束的添加。如今你给视图添加了两个新约束,一个是宽度160点的约束,一个是高度284点的约束:

由于宽和高仅应用在当前视图,因此它们在Outline文档中位于本身的view下面。通常来讲,约束都表达了两个不一样view之间的某种关系 - 例如:横向间距和纵向间距(Horizontal and Vertical Space)约束就是绿色视图与它父视图的关系 - 你也能够认为宽度和高度约束是绿色视图和它本身的约束。

运行app,噢,看起来多棒啊。如今把你的屏幕横置,哎哟!没有像你想的那样 - 视图的尺寸再次该变 - 而是报错了,Xcode给出了一堆错误的信息:


Gallery[39367:a0b] Unable to simultaneously satisfy constraints.
        Probably at least one of the constraints in the following list is one you don't want. Try this: 
     (1) look at each constraint and try to figure out which you don't expect; (2) find the code that 
     added the unwanted constraint or constraints and fix it. (Note: If you're seeing 
     NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for 
     the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0xc1a1e80 V:[UIView:0xc1a2b10(284)]>",
    "<NSLayoutConstraint:0xc1a36c0 V:[_UILayoutGuide:0xc1a2d20]-(65)-[UIView:0xc1a2b10]>",
    "<NSLayoutConstraint:0xc1a36f0 V:[UIView:0xc1a2b10]-(199)-[_UILayoutGuide:0xc1a3230]>",
    "<_UILayoutSupportConstraint:0xc15dbd0 V:[_UILayoutGuide:0xc1a2d20(20)]>",
    "<_UILayoutSupportConstraint:0xc1a1510 V:|-(0)-[_UILayoutGuide:0xc1a2d20]   (Names: '|':UIView:0xc1a2930 )>",
    "<_UILayoutSupportConstraint:0xc1a3720 V:[_UILayoutGuide:0xc1a3230(0)]>",
    "<_UILayoutSupportConstraint:0xc1a30e0 _UILayoutGuide:0xc1a3230.bottom == UIView:0xc1a2930.bottom>",
    "<NSAutoresizingMaskLayoutConstraint:0x8c6c6a0 h=--& v=--& H:[UIView:0xc1a2930(320)]>"
)
 
Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xc1a1e80 V:[UIView:0xc1a2b10(284)]>
 
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
 
. . .

你还记得我说过“必须有足够的约束,自动布局才能计算全部视图的位置和尺寸”么?好吧,在这个例子中,约束又太多了。当你看到“不能同时知足全部约束(Unable to simultaneously satisfy constraints)”的错误的时候,那就意味着你的约束之间有冲突。

让咱们再看一下哪些约束:

绿色视图上设置了6个约束,4个间距约束(1-4)和你刚刚设置的宽高约束(5和6)。冲突在哪呢?

在竖屏的时候不该该有问题,由于在数学上是知足的。父视图的宽是320点。若是你添加了Horizontal Space和Width约束,你应该保证它们的总长度小于等于320点。这是我计算视图位置的方式:98+160+62 = 320。一样的,全部竖向约束相加之后就应该是568点。

可是当你旋转设备为横屏时,窗口(指的父视图)就变成了568点宽。这意味着98+160+62+? = 568。这里额外多了248点,没法知足方程式,因此自动布局不知道从哪里来获得这248点。一样的,对于竖向约束也是同样。

解决冲突的办法有两个:第一是保持view的宽度固定,但外边距必须可变。第二是保持外边距固定,但宽度必须可变。你不能同时固定它们。你要去掉这些约束中的其中一个。在上面的例子中,若你想要在横屏竖屏中都拥有一样的宽,那Horizontal Space就必须去掉。

移除右边的横向间距和下边竖向间距。故事板上会显示成这样:

好了,如今view就有一个正确约束来预判它的尺寸与位置了 - 很少,很多。运行app来查证一下错误信息是否已经没有了,而后这个view在旋转之后是否能保持宽度。

注意:尽管Interface Builder能够很好的警告你有无效的约束,但它不是神。它只会警告你:噢,你的约束不够。可是若是你约束太多了,它就没法检测出来了。不过至少在出错的时候,自动布局仍是会给出一个详细的错误信息。若是你想要学习更多关于如何分析错误信息和诊断布局问题,那你能够看 iOS 6 by Tutorials中的“Intermediate Auto Layout”。

竖屏绘制

拖拽一个label到绿色的view上。注意看,如今参考线出如今了绿色view的内部,由于它是label的父视图。

调整label的位置到参考线的下边距,横向居中的地方。给label下面添加与绿色view之间的间距约束,有20点的距离。快速的方式是使用Pin按钮,仅选择下面的T字架:

如今给label添加横向居中的约束。你已经试过Editor\Align菜单了,但你也可使用自动布局菜单的Align按钮。选择label并点击Align按钮,获得一个弹出窗:

在Horizontal Center前打上勾而后点击Add 1 Constraint。这时候,故事板应该是这个样子的:

注意这两个新的横向和纵向间距约束是位于绿色view本身的约束列表里,而不是在主视图里。

拖拽一个新的Image View对象到故事板上,让你的布局看起来像这样::

这个图片视图固定了上,左,右边缘在父视图上,但下部以标准的8点间距链接在了label的顶部。若是你不肯定要怎么作,那就跟着下面的步骤走:

1. 拖拽image view到绿色视图中,如今不用担忧它的尺寸和位置:

2. 选中image view,按Pin按钮选择下面的选项:

上,左,右的T字架设置为20点,可是下面的设置为8点。重点:对于Update Frames,你应该选择Items of New Constraints。若是你左边距已经默认知足要求,故事板看起来就是这样的:

上面这个约束是你选择了一个不同的frame。若是你选择了Items of New Constraints, Interface Builder将自动的调整画面来添加约束,一切看起来都很棒:

固然,若是你选错了frame,你也可使用Resolve Auto Layout Issues button来修复它:

下载这个教程资源并解压这个文件。你就会找到一个图片文件夹 - 添加这个文件夹到你的项目。设置Ray.png做为这个image view的图片,改变image view的模式为Aspect Fit而且设置它的背景色为白色。把label的文本改成“Ray”。

你的布局应该是这样的:

你可能注意到绿色view内部的约束忽然变成了橘黄色。这发生在你给image view设置图片的时候。你的布局为何忽然无效了?幸运的是你能够带着你的猜测来让Xcode告诉你为何错处了。

点击这个这个红色的靶子,它位于View控制器的Outline文档中:

你会看到一个Content Priority Ambiguity(内容优先级歧义)的错误。这意味着:若是image view和label都没有固定的高度,那自动布局系统就不知道应该怎么分配大小。(Interface Builder彷佛会忽略已经设置过的固定高度约束)

让咱们把绿色的view的高度变为100点试试。自动布局是怎么将这100点分配给view内部的label和image view的?是label保持尺寸而image view变成100点高了么?仍是label变高了而image view保持尺寸?仍是他们各自被分配了50点,又或者划分红25/75,40/60,又或者其它的什么结合?

若是你不解决这个问题,那么自动布局系统就会去猜想,就可能致使结果莫名其妙。

恰当的解决办法是改变label的“Content Compression Resistance Priority”。你将从随后内容中学习到更多。如今,打开label的Size inspector,设置Content Compression Resistance Priority的vertical为751。这样就使它的优先级高于image view。而后继续设置Content Hugging Priority为252。

这时候T字架就会再次变成蓝色,自动布局系统的警告也会消失。

添加到另外一个顶端

拖拽绿色的view到主视图的左上角。回忆一下以前作过的,绿色的view已经有Horizontal Space和Vertical Space约束来控制它在父视图中的位置了。如今,这些约束依然存在,它们致使了视图的frame没法对齐参考线。

为了修正它,使用Resolve Auto Layout Issues按钮并选择Update Constraints。以前你使用的Update Frames,用来移动和重定义view的尺寸来匹配你的约束。如今这恰好是一个相反的操做:你会用你的约束来匹配view的frame。

你可能注意到在顶部的Vertical Space如今是负的。这种状况是由于约束连接到了Top Layout Guide(顶部参考线)。不要问为何,没有规定说约束值不能是负的,你能够就像这样留下它。(若是你看着碍眼,那就删掉 “Vertical Space (-20)”约束,而后把view从新绑定到窗口的顶部)

Horizontal Space如今为0,表现为一条紧贴窗口左边缘的粗蓝线。尽管view已经位于角落里了,可是它任然须要约束来固定住它:

选择绿色的视图按下⌘D来复制它。移动复制的视图到右上角:

注意T字架如今是橘黄色的。当你复制它的时候,它已经上丢失了X,Y坐标的约束。为了修正它,固定view到窗口的右、上边缘。

再复制两次,分别把复制的视图放在坐下角落和右下角落。而后再把他们固定在他们该在地方。

改变后的场景以下:

 

哈哈~他们看起来好像都是程序员 :-)

运行app,在竖屏上很棒,可是横屏上可能不是那么好:

原本应该很棒的战士却变糟了:你给4个色彩鲜艳的容器view设定了固定的宽和高,所以它们就老是保证这样的尺寸,而无论它们的父视图的尺寸如何。

从这4个view下,选择Width (160)和Height (284)的约束并删除它们(在Outline文档中很容易完成)。若是你如今运行app,你会看到:

注意:若是你很奇怪为何有的view变得比其余的大了,那我告诉你,这是固有内容尺寸的缘由。图片的尺寸决定了image view有多大。文本的尺寸决定了label有多大。再加上四边的20点外边距,全部的尺寸加起来决定了每一个视图的尺寸。

这看起来很像你的上一部分解决的问题,所以你要向前思考,你可能回忆起来了,你要让每一个view的宽和高都相等。

选择这4个view。Outline大纲里很容易完成;按住⌘点击这4个view。你就能够添加这个约束。在弹出窗中,给Equal Widths和Equal Heights打上勾,而后点击Add 6 Constraints。

再次运行这个app而且旋转设备。噢...仍是不咋地:

全部的view都有一样的高,而且他们也有一样的宽,你的约束是对的。但这个宽和高可能不是你想要的。

光告诉自动布局系统必须有一样的尺寸是不够的。由于自动布局系统不知道这4个view是互相链接的。它们的边贴边的设计,但在它们之间没有这样的约束。自动布局就不知道它须要在“Ray”个“Matthijs”之间划分窗口。

若是自动布局系统本身不能完成,那你就要告诉它。

 

选择Ray和Matthijs的视图,从编辑菜单选择Pin\Horizontal Spacing。由于view之间是边贴边的,那在它们之间就要加上尺寸为0的Horizontal Space约束。好了,如今有足够的约束让自动布局系统了解两个view之间的关系了。再给Ray和Dennis Ritchie视图之间使用Editor\Pin\Vertical Spacing。

再运行app,如今看起来就像这样:

注意:Interface Builder任然会抱怨view的位置不对。我不确信为何会发生这种状况,多是Xcode有bug吧。若是这些警告信息让你不爽,那就选择主视图(或view控制器)而且从Resolve Auto Layout Issues菜单选择Update All Frames in View Controller。不过你的app运行时这种改变不会起做用,但至少让Xcode看起来很舒心。

image view上有一点要注意:它们可能会延伸了,由于你没有给它们一个固定尺寸。你可能不知道,这是有意这样作的。image view不能适配横屏的模式。若是你想保持image view的原始宽高比,那很不幸。在Interface Builder中你是没法获得下面这样的效果的:

 

 

 

 

Demo代码:

不幸的是,Interface Builder不能正确的提供用约束保持view的原样宽高比。若是要这么作,你就须要本身编程。你能够在iOS 6 by Tutorials的“Intermediate Auto Layout”中学习如何操做。

我该去哪继续学习?

若是你全都看完作完了,祝贺你 - 你如今知道自动布局是什么了,而且有了必定的实践基础!但你任然有许多须要学习...

这个教程的第一部分你能够从iOS 6 by Tutorials一书中的自动布局章节阅读到。第二部分会教你如何使用自动布局来建立更多“真实世界”的场景布局,你能够从Interface Builder学习一切你想知道的自动布局的知识。

可是就像其余的视觉设计工具同样,Interface Builder也有本身的局限性。有时,它只能经过NSLayoutConstraint对象来从代码实现。IOS 6的教程有一个章节包含了这个主题全部的内容,Intermediate Auto Layout。所以,若是你想知道自动布局的后半部分,请买这本书吧!(翻译到最后,发现竟然带广告,为了尊重原做者,仍是给出链接吧~~~)

相关文章
相关标签/搜索