IOS 6 自动布局--Auto Layout

来源:互联网 发布:数控车床g73编程实例 编辑:程序博客网 时间:2024/04/30 05:40

随着iOS 6正式版和OS X 10.8.2正式版发布之后,苹果还向开发者发布了其应用开发工具Xcode最新版,在最新的Xcode 4.5版本中增加了:

 自动布局对OS X和iOS的支持;

 同时也增强了对MacBook Pro的Retina显示屏支持;

 及对Objective-C的一些优化。下面来研讨一下自动布局对OS X和iOS的支持!!

通常来说,如果屏幕是固定尺寸,那么设计它的用户界面不会很难,但如果屏幕的frame需要能够变化,那么其中各个UI元素的位置以及尺寸也必须为了适应新的尺寸做相应的变化。

目前为止,即使你的界面设计是在合理的复杂度内,你也必须要为之写许多代码来适应变化的布局。现在我相信你会很高兴听到这种情况将不会发生了-对于iPhone与iPad IOS6 带来了一个非常了不起的特征:自动布局。

自动布局不仅能给你的应用带来各种屏幕尺寸设计的支持,做为额外的惊喜,它还能使设计中的各种小事比如多语言环境支持。你从此不必再为你想要支持的各种语言重新设计nibs和storyboards文件,当然这也包括一些从右至左书写的语言比如说希伯来文和阿拉伯语。

这篇教程将向你展示的是如何开始使用Iterface Builder来做自动布局。

springs and struts 的问题

毫无疑问你可能对autosizing masks比较熟悉–这个也就是 “springs and struts” 模式。autosizing mask决定了一个view会发生什么当它的superview 改变大小的时候。它是否有灵活并且自动修复页边处理能力(the struts),它的宽和高同时也会发生什么变化呢(the springs)?

举个例子,当一个view的superview的宽度变宽时,它的宽度也会灵活地跟着变宽,并且它的右边界也会自动修复般的一直紧挨着superview的右边界。

autosizing 系统处理这种简单的情况还是不错的,但是当情况稍微复杂一点的时候,它就会很快搞砸你的布局。现在让我们看一个springs and struts模式所不能处理的一个简单例子吧。

打开Xcode创建一个基于Single View Application template新项目,把之命名为”StrutsProblem”,选择iPhone程序并且禁用Storyboards:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

在 Interface Builder 里点击打开ViewController.xib。在你做任何其他事情之前,请先在nib里把Auto Layout禁用掉。你可以在File inspector里找到这个选项:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

取消选择“Use Autolayout”复选框. 那么现在你的nib使用的是旧版本的 struts-and-springs 模式。

提示: 任何你通过Xcode4.5或者更高版本创建的新nib或者storyboard文件会默认使用Auto Layout。因为Auto Layout这个特性只有在IOS 6中有,所以如果你想要使用 Xcode4.5来做一些兼容IOS5的应用,你必须要在新的nib或者storyboard文件中通过取消选择“Use Autolayout”复选框来禁用Auto Layout。

拖拉三个新的view到main view中,如图所示:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

为了使看起来更清晰,我们把每个view都填注颜色。

现在每个View都离窗体边界 20 points远;各个填充颜色的view之间的距离也是20 points。底部的view是280 points宽,并且顶部两个view都设置成130 points宽。所有的view都设置成200 points 高。

运行程序并且把模拟器或者你的设备旋转至景观方向。你的设备会如下图所以,和我们理想的差距甚远:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

提示:你能够通过使用 HardwareRotate Left and Rotate Right的菜单选项来旋转模拟器, 或者通过按住Cmd然后使用向左或者向右方向键来旋转。

而我想要的是让程序运行后是这个样子的在景观方向下:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

很明显, autosizing masks 对于要达到这三个view的理想变化还需要做点其他的。 从左上角的View来开始设置autosizing :

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

这一步使View能紧挨着顶部和左边缘(而不是底部与右边缘),并且在水平和垂直方向上都能够支持伸缩当superview改变其大小时。

类似地, 改变 右上角autosizing 设置:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

这是底部view的设置:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

运行程序并且转动设备至景观方向。现在应该看上去是这样:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

和理想的很接近了,但是还有点瑕疵。三个view之间的距离是不正确的。另外仔细看,这三个view的尺寸也不是100%正确. 造成这个原因是autosizing masks虽然知道要改变view的尺寸当superview改变时,但是它不知道具体该改变多少尺寸。

你可以玩一下 autosizing masks-比如说,改变可以改变的宽和高的值(“springs”)- 但是你几乎不可能精确设置到20-points的距离在三个view之间。

为了解决使用 the springs and struts 方式改变布局所造成的问题,很不幸的,你必须要写一些代码来做。

UIKit 会发送一些消息到你的view controllers当用户界面在开始旋转前,在旋转过程中以及旋转后。你可以通过监听这些消息来改变你用户界面的布局。通常你会重写willAnimateRotationToInterfaceOrientation:duration: 来改变任何需要重新规划的view的frame。

但在你开始做这之前, 你首先需要声明views里面的outlet 属性。

Xcode切换到 the Assistant Editor 模式(在Xcode工具栏的右上角的编辑器工具包的中间一个按钮)然后把每个view拖拉至view controller:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

逐个把这些view与属性连接起来:

@property (weak, nonatomic) IBOutlet UIView *topLeftView;

@property (weak, nonatomic) IBOutlet UIView *topRightView;

@property (weak, nonatomic) IBOutlet UIView *bottomView;

Add the following code to ViewController.m:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

{

[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

 

if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft

toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)

{

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 设置如下图所示,否则 autosizing 机制会与你在 willAnimateRotation: 函数设置里的view的位置、尺寸产生冲突。

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

现在可以运行程序了,然后将设备翻转至景观方向。可以看到每个view的呈现都很理想,再次翻准屏幕至肖像方向,看上去也还不错。

这样做成功了,但是为了这么个简单的呈现你就要必须写许多代码了。想象一下,当你遇到真正更加复杂,特别是动态的那些独立View改变尺寸,或者有一系列的subviews没有被固定时你在代码上所需要作出的努力。

提示: 你还可以使用另外一种方法,那就是同时做好肖像方向以及景观方向的nib,然后当设备转动时,把对应的view从nib文件载入进来,把当前的view交换出去。但即使这样,你还是需要做很多的工作,另外你还多了同时管理两个nib文件而不是一个nib文件的麻烦。

Auto Layout 来拯救了!

现在我将要展示的是如何用Auto Layout来做到同样的效果。首先,把willAnimateRotationToInterfaceOrientation:duration:这个方法从ViewController.m里面删除,因为目前我要做的Auto Layout是不需要写任何代码的。

回到ViewController.xib然后在File inspector控制面板里,把“Use Autolayout”的复选框勾上使Auto Layout对这个nib文件起作用:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

提示: Auto Layout 功能在整个nib或者storyboard文件里总是被开启着的。在这两种文件里的所有view都会使用Auto layout功能如果你把勾选上的话。

现在运行程序并且转动屏幕,呈现的样子还是之前的混乱样。

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

现在让我们启动Auto Layout功能. 按住Cmd键同时选中顶部的两个view (绿色的以及黄色的),。 从 Xcode的Editor 菜单, 选择Pin Widths Equally:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

再次重新选中这两个view并且做 Editor_Pin_Horizontal Spacing操作。 (即使这两个view看上去像被选中了当你做第一个Pin操作后。但是请注意目前他们处在一种特殊的布局关系显示模式中,你还是必须要重新选中这两个view。)

在左边的文档概要图中, 你会注意到有一个新的section名叫 “Constraints”. 这个section 会被自动加入当你在nib文件中启用Auto Layout时。在这篇文档的下一部分你会了解到这些Contraints是什么以及他们是如何操作的。

现在, 我们把一个名叫  “Horizontal Space (170)” 的从Constraints列表里面删除:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

运行程序并转动屏幕. 现在看上去好多了 – 顶部的两个view 有了合适的宽度和间距 – 但还不是我们想要的样子:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

按住Cmd键同时选中所有的三个view。在菜单栏, 做Pin_Heights Equally 操作。

现在还是按住Cmd键同时选中左上角的以及底部的view,然后做Editor_Pin_Vertical Spacing 操作。

最后,把“Vertical Space (240)” 从constraint列表里面删除。

如果你一下子同时选中所有的三个view,Interface Builder应该如下图所示:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

蓝色的T型状对象定义了各个view之间的限制。这看上去有点复杂, 但是你一旦学会了,你会发现这种表达相当简洁明了。

运行程序 … 哇, 没有写一行代码每样东西都看上去非常棒了!

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

酷, 但刚才你究竟做了什么呢?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以及它是如何工作的。

提示: springs-and-struts布局模式也会带来一些其他限制当你从它切换至“Use Autolayout”模式时。对于各个view和屏幕边缘之间的边距都基本会有一条限制,是这么说的:“这个view总是和顶部/底部/左边/右边保持着20-points的距离。”

你可以看到你的所有contraints在文档概要里。如果你在文档概要里点击一个constraint,Interface Builder会在contraint在view中所体现的地方通过画一条白色的边框并且对之添加一个阴影使其高亮显示:

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)

Constraints是真实的对象 (属于 NSLayoutConstraint类) ,他们也拥有相应的属性。比如说,选中顶部两个view间距的constraint(名为“Horizontal Space (20)”)然后切换至它的Attributes inspector。现在你可以通过修改Constant里的值来改变两个view之间的距离大小。

最新iOS <wbr><wbr>6 <wbr><wbr>in <wbr><wbr>Xcode4.5新特性编程之一鈥斺斪远季(1)


原创粉丝点击