springs和struts的问题
你肯定非常熟悉autosizing masks-也被觉得是springs&struts模式。autosizing mask决定了当一个视图的父视图大小改变时,其自身须要做出什么改变。它有一个灵活的或固定不变的margins(struts)吗?它的宽和高要做出什么改变(springs)?
举个样例,一个宽度灵活的视图,假设其父视图边框,那么它也会对应的变宽。一个视图右边拥有固定的margin,那么它的右边缘将会一直粘住其父视图的右边缘。
autosizing系统在简单的情况下很奏效,但当你布局变得更复杂时,它立刻跪了。让我们看一个springs和struts不能处理的演示样例。
打开Xcode5,创建一个基于Single View Application模板的iPhone项目。叫做"StrutsProblem":
点击Main.storyboard。在你做别的之前,首先将这个storyboard的自己主动布局关了。你须要在File inspector,第一个选项的第六个tabs里:
将Use Autolayout的box勾选去掉。如今storyboard使用旧的struts-and-springs模型。
注意:不论什么你使用Xcode4.5或更高版本号中,nib或者storyboard文件都默认激活了自己主动布局。由于自己主动布局是iOS6以及以上系统的一个新特性,假设你想使用最新的Xcode开发兼容iOS5的程序,你须要将这个选项去掉。
拖拽三个新的视图到主视图上,而且像这样排列起来:
为了表述更清楚,这里给出每一个视图的颜色,这样你就能分清哪个是驴子哪个是马了。
每一个视图的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中去:
分别链接视图到这三个属性:
- @property (weak, nonatomic) IBOutlet UIView *topLeftView;
- @property (weak, nonatomic) IBOutlet UIView *topRightView;
- @property (weak, nonatomic) IBOutlet UIView *bottomView;
以下的代码写到ViewController.m:
- - (void)viewWillLayoutSubviews
- {
- if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
- {
- CGRect rect = self.topLeftView.frame;
- rect.size.width = 254;
- rect.size.height = 130;
- self.topLeftView.frame = rect;
- rect = self.topRightView.frame;
- rect.origin.x = 294;
- rect.size.width = 254;
- rect.size.height = 130;
- self.topRightView.frame = rect;
- rect = self.bottomView.frame;
- rect.origin.y = 170;
- rect.size.width = 528;
- rect.size.height = 130;
- self.bottomView.frame = rect;
- }
- else
- {
- CGRect rect = self.topLeftView.frame;
- rect.size.width = 130;
- rect.size.height = 254;
- self.topLeftView.frame = rect;
- rect = self.topRightView.frame;
- rect.origin.x = 170;
- rect.size.width = 130;
- rect.size.height = 254;
- self.topRightView.frame = rect;
- rect = self.bottomView.frame;
- rect.origin.y = 295;
- rect.size.width = 280;
- rect.size.height = 254;
- self.bottomView.frame = rect;
- }
- }
当视图控制器旋转到一个新的方向,这个回调将会被调用。它会监控视图控制器旋转的方向,而且适当的调整视图大小-在这样的情况,依据已知iPhone屏幕大小会有一个hard-code(将可变变量用一个固定值来取代的方法叫做hard-code)偏移。这个回调会在一个动画block中发生,所以会动态的改变大小。
临时还不要执行这个程序。首先你须要按以下的样子又一次保存三个视图的autosizing masks,否则autosizing mechanism将会和你在viewWillLayoutSubviews中设置的位置和大小冲突。
这样就能够了,执行程序而且翻转到landscape。如今视图排列的很号。翻转回到portrait,经核实,一切都良好。
这样奏效了,可是你须要为这个很easy的样例编写大量的布局代码。想象一下,为布局付出的努力是很复杂的,特别是个别视图动态的改变大小,或者子视图的个数是不固定的。
如今试着在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中的动态类型,自己主动布局变得更加重要了。用户如今能够改变全局字体大小设置--有了自己主动布局,这将变得很easy。
拥抱约束(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,让我们玩一玩约束并看看他们能做什么。如今,button是在左上角,而且没有约束。确认button跟两个拐角向导线对齐。
使用Editor\Pin菜单为button添加两个新的约束,看起来像这样:
这是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轴没有约束了。
这样的缺失约束的情况是非常easy确定的,可是更复杂的设计可能就没这么明显了。幸运的是,你不再须要敏思苦想,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可能不大easy看到,但它就在那里。
点击Document Outline里面的Horizontal Space(8):
当你选中一个约束,它会高亮自己所属的控制器。这个特别的约束位于两个button之间。这个约束表达了:“无论第一个button在哪儿或多大,第二个button总是出如今第一个button的左边”。
选中黄色背景的button并输入较长的label,比方:“A longer label”。输入完毕后,button会为新的text改变大小,而且还有一个button会移开。
终于,它依附在第一个button的左边缘,这正是我们所期望的:
为了更好的摸索这是怎样工作的,多练一些吧。拖拽还有一个button到画布上并放到黄色button的上方,他们会垂直方向对齐到位(不要试着让两个button的左边缘对齐):
为新button设置一个绿色背景色,这样就能够更easy看出它的范围。
由于你将两个button对齐在一起,如今他们之间存在HIG推荐的8 points间隔。按住Ctrl在两个button之间拖拽将这变为一个约束。从弹出菜单中选中Vertical Spacing。
然而你并没有被限制在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更加灵活。