随着iOS 6正式版和OS X 10.8.2正式版发布之后,苹果还向开发者发布了其应用开发工具Xcode最新版,在最新的Xcode 4.5版本中增加了:
通常来说,如果屏幕是固定尺寸,那么设计它的用户界面不会很难,但如果屏幕的frame需要能够变化,那么其中各个UI元素的位置以及尺寸也必须为了适应新的尺寸做相应的变化。
目前为止,即使你的界面设计是在合理的复杂度内,你也必须要为之写许多代码来适应变化的布局。现在我相信你会很高兴听到这种情况将不会发生了-对于iPhone与iPad IOS6 带来了一个非常了不起的特征:自动布局。
自动布局不仅能给你的应用带来各种屏幕尺寸设计的支持,做为额外的惊喜,它还能使设计中的各种小事比如多语言环境支持。你从此不必再为你想要支持的各种语言重新设计nibs和storyboards文件,当然这也包括一些从右至左书写的语言比如说希伯来文和阿拉伯语。
这篇教程将向你展示的是如何开始使用Iterface Builder来做自动布局。
springs and struts 的问题
毫无疑问你可能对autosizing masks比较熟悉–这个也就是
举个例子,当一个view的superview的宽度变宽时,它的宽度也会灵活地跟着变宽,并且它的右边界也会自动修复般的一直紧挨着superview的右边界。
autosizing 系统处理这种简单的情况还是不错的,但是当情况稍微复杂一点的时候,它就会很快搞砸你的布局。现在让我们看一个springs and struts模式所不能处理的一个简单例子吧。
打开Xcode创建一个基于Single View Application template新项目,把之命名为”StrutsProblem”,选择iPhone程序并且禁用Storyboards:
在 Interface Builder 里点击打开ViewController.xib。在你做任何其他事情之前,请先在nib里把Auto Layout禁用掉。你可以在File inspector里找到这个选项:
取消选择“Use Autolayout”复选框. 那么现在你的nib使用的是旧版本的
提示:
拖拉三个新的view到main view中,如图所示:
为了使看起来更清晰,我们把每个view都填注颜色。
现在每个View都离窗体边界 20 points远;各个填充颜色的view之间的距离也是20 points。底部的view是280 points宽,并且顶部两个view都设置成130 points宽。所有的view都设置成200 points 高。
运行程序并且把模拟器或者你的设备旋转至景观方向。你的设备会如下图所以,和我们理想的差距甚远:
提示:你能够通过使用
而我想要的是让程序运行后是这个样子的在景观方向下:
很明显, autosizing masks 对于要达到这三个view的理想变化还需要做点其他的。 从左上角的View来开始设置autosizing :
这一步使View能紧挨着顶部和左边缘(而不是底部与右边缘),并且在水平和垂直方向上都能够支持伸缩当superview改变其大小时。
类似地, 改变 右上角autosizing 设置:
这是底部view的设置:
运行程序并且转动设备至景观方向。现在应该看上去是这样:
和理想的很接近了,但是还有点瑕疵。三个view之间的距离是不正确的。另外仔细看,这三个view的尺寸也不是100%正确. 造成这个原因是autosizing masks虽然知道要改变view的尺寸当superview改变时,但是它不知道具体该改变多少尺寸。
你可以玩一下
为了解决使用
UIKit 会发送一些消息到你的view controllers当用户界面在开始旋转前,在旋转过程中以及旋转后。你可以通过监听这些消息来改变你用户界面的布局。通常你会重写willAnimateRotationToInt
但在你开始做这之前, 你首先需要声明views里面的outlet 属性。
Xcode切换到 the Assistant Editor 模式(在Xcode工具栏的右上角的编辑器工具包的中间一个按钮)然后把每个view拖拉至view controller:
逐个把这些view与属性连接起来:
@property (weak, nonatomic) IBOutlet UIView *topLeftView;
@property (weak, nonatomic) IBOutlet UIView *topRightView;
@property (weak, nonatomic) IBOutlet UIView *bottomView;
Add the following code to
- (void)willAnimateRotationToInt
{
[super willAnimateRotationToInt
if (toInterfaceOrientation == UIInterfaceOrientationLa
toInterfaceOrientation == UIInterfaceOrientationLa
{
CGRect rect = self.topLeftView.frame;
rect.size.width = 210;
rect.size.height = 120;
self.topLeftView.frame = rect;
rect = self.topRightView.frame;
rect.origin.x = 250;
rect.size.width = 210;
rect.size.height = 120;
self.topRightView.frame = rect;
rect = self.bottomView.frame;
rect.origin.y = 160;
rect.size.width = 440;
rect.size.height = 120;
self.bottomView.frame = rect;
}
else
{
CGRect rect = self.topLeftView.frame;
rect.size.width = 130;
rect.size.height = 200;
self.topLeftView.frame = rect;
rect = self.topRightView.frame;
rect.origin.x = 170;
rect.size.width = 130;
rect.size.height = 200;
self.topRightView.frame = rect;
rect = self.bottomView.frame;
rect.origin.y = 240;
rect.size.width = 280;
rect.size.height = 200;
self.bottomView.frame = rect;
}
}
当view controller旋转至一个新的方向时会调用这个回调函数。现在当用户界面的方向转动时view controller使它里面的view尺寸缩放理想了- 这是一种建立在对iPhone屏幕尺寸了解上的硬编码能力。因为这个回调函数发生在一个动画block里,所以当改变它的尺寸会有动画效果。
等等,现在还不能运行程序。你必须先恢复这三个view的autosizing masks 设置如下图所示,否则
现在可以运行程序了,然后将设备翻转至景观方向。可以看到每个view的呈现都很理想,再次翻准屏幕至肖像方向,看上去也还不错。
这样做成功了,但是为了这么个简单的呈现你就要必须写许多代码了。想象一下,当你遇到真正更加复杂,特别是动态的那些独立View改变尺寸,或者有一系列的subviews没有被固定时你在代码上所需要作出的努力。
提示:
Auto Layout 来拯救了!
现在我将要展示的是如何用Auto Layout来做到同样的效果。首先,把willAnimateRotationToInt
回到ViewController.xib然后在File inspector控制面板里,把“Use Autolayout”的复选框勾上使Auto Layout对这个nib文件起作用:
提示:
现在运行程序并且转动屏幕,呈现的样子还是之前的混乱样。
现在让我们启动Auto Layout功能. 按住Cmd键同时选中顶部的两个view
再次重新选中这两个view并且做
在左边的文档概要图中, 你会注意到有一个新的section名叫 “Constraints”. 这个section 会被自动加入当你在nib文件中启用Auto Layout时。在这篇文档的下一部分你会了解到这些Contraints是什么以及他们是如何操作的。
现在, 我们把一个名叫
运行程序并转动屏幕. 现在看上去好多了 – 顶部的两个view 有了合适的宽度和间距 – 但还不是我们想要的样子:
按住Cmd键同时选中所有的三个view。在菜单栏, 做Pin_Heights Equally 操作。
现在还是按住Cmd键同时选中左上角的以及底部的view,然后做Editor_Pin_Vertical Spacing 操作。
最后,把“Vertical Space (240)” 从constraint列表里面删除。
如果你一下子同时选中所有的三个view,Interface Builder应该如下图所示:
蓝色的T型状对象定义了各个view之间的限制。这看上去有点复杂, 但是你一旦学会了,你会发现这种表达相当简洁明了。
运行程序 … 哇, 没有写一行代码每样东西都看上去非常棒了!
酷, 但刚才你究竟做了什么呢?Auto Layout 能使你简单地表达清楚页面布局中的各个view之间的关系而不会让你为了各种view有多大以及他们该定位在哪里硬编许多代码 。
你刚才做了如下的关系操作 – 也就是 constraints – 在页面布局里:
左上角和右上角的view (也就是第一次的pin widths equally 操作).
在左上角view和右上角view之间有20-point的间距 (相应的操作是 pin horizontal spacing).
所有的view是相同的高度 (相应的操作是pin heights equally).
在顶部两个view与底部的view之间有一个20-point的间距 (the pin vertical spacing).
以上这些就足以展示,当屏幕尺寸变化时,Auto Layout如何放置布局里的各种view以及它是如何工作的。
提示:
你可以看到你的所有contraints在文档概要里。如果你在文档概要里点击一个constraint,Interface Builder会在contraint在view中所体现的地方通过画一条白色的边框并且对之添加一个阴影使其高亮显示:
Constraints是真实的对象 (属于