IOS - 屏幕适配

原文:Beginning Auto Layout Tutorial in iOS 7: Part 1html

感谢翻译小组成员@answer-huang博客)热心翻译。若是您有不错的原创或译文,欢迎提交给咱们,更欢迎其余朋友加入咱们的翻译小组(联系qq:2408167315)。ios

==========================================================================spring

提示:团队成员Jatthijs Hollemans(iOS 初级系列做者)已经将这篇文章移植到iOS7 feast。但愿你可以喜欢。app

你是否曾经想让你的app在横竖屏方向上看起来都表现良好而受挫?是否在作支持iPhone和iPad屏幕布局界面时几近大小便失禁?今天我将给你带来好消息!
 
一直为大小相同的屏幕设计一个用户界面并不难,但若是屏幕的尺寸改变的话,UI元素的位置和大小也须要相应的作出改变。
 
到目前为止,若是你的设计至关的复杂,那么你必须编写大量的代码来适应这样的布局。你应该很高兴,如今这样的状况不再存在了--iOS6为iPhone和iPad带来了一个极好的新特性:自动布局。Xcode 5和 iOS7中对自动布局作出了改善!若是你曾经尝试着在Xcode4中使用自动布局并最终作出放弃,如今是该给Xcode5一次机会了。
 
在你的程序中,自动布局不只能够很容易的支持不一样大小的屏幕,一个额外的功能,它也使得本地化几乎变得微不足道。你再也不须要为每种你但愿支持的语言建立新的nibs或storyboards,包括像Hebrew或Arabic这样从右到左的语言。
 
这个教程将向你展现如何使用Interface Builder开始自动布局.在 iOS6 教程中,咱们进一步讨论过这个教程,而后有一个基于这个知识点完整的新章节,而且向你展现如何经过代码彻底释放出自动布局的能量。
 
注意:咱们已经开始将iOS6教程中相应的章节更新到iOS7-这只是先给你们解解馋!当咱们完成后,全部iOS6 PDF教程的订阅者将会获得免费的更新下载。
 
so,备好零食和你喜欢的咖啡,准备成为自动布局的达人吧!
 
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中去:
 
分别连接视图到这三个属性:
  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.
 
oTop Space to Superview
oLeading Space to Superview
For the view on the right, choose:
oTop Space to Superview
oTrailing Space to Superview
And for the big view at the bottom:
oLeading Space to Superview
oTrailing Space to Superview
oBottom 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在一个真实的程序中建立一个逼真的布局。
相关文章
相关标签/搜索