对于iOS开发者来说,安卓平台下几乎无限种类的屏幕尺寸适配问题曾经臭名昭著。从iOS的角度去看,这确实曾经是个难题,因为iOS平台并没有提供太多解决方案以应对此事。
如果你尝试创建一个既支持iPhone又支持iPad的通用型应用,最终你将不得通过很多类似“if deviceType == kIpad” 的代码来实现。
自动布局(AutoLayout)是解决这个问题的第一步,而iOS 8下的size classes则是它的终结。在iOS 8的新特性中关于这一点的介绍可能缺乏吸引力,但无疑它是非常重要的。
关于size classes的一些核心背景
现在有两种尺寸类型:水平(horizontal)和垂直(vertical),各有两种规格:常规(regular)和紧凑(compact)。当前的设备方向能够被各种尺寸组合所描述:
•Horizontal regular, vertical regular: 任意方向的iPad
•Horizontal compact, vertical regular: 竖屏iPhone
•Horizontal regular, vertical compact: 未知设备
•Horizontal compact, vertical compact: 横屏iPhone
Storyboard 和 nib文件现在已经支持这些size classes,所以你可以在同一个文件中考虑使用四种布局方式。在Interface Builder底部有控件允许你在每种组合间进行切换。
每一个控件或自动布局的约束可以在一个或多个size classes中存储,这意味着你不用写一行代码就可以根据设备类型或设备方向进行界面的定制:控件隐藏或显示、改变大小,改变对其方式等,所有这些你都可以在Interface Builder中完成
检测 size classes
为了示范在设备旋转过程中size classes是如何变化的,你可以通过使用一个新的回调方法来捕获界面变化。
-(void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator { NSLog(@"Trait collection = %@", newCollection); }
它将打印每个旋转触发时size classes的相关信息
2014-08-16 19:04:49.785 Adaptr[6522:213857] Trait collection =
如何构建自适应布局
为了示范这一点,这里有一个简单的依据设备不同和方向旋转而改变界面布局的通用型应用,你可以从这里下载,或者从这里一步步开始,我现在假设你至少在使用Xcode 6 Beta5。
首先,建立一个基于Single View的通用型应用程序,它将建立一个App Delegate,一个视图控制器和一个Storyboard。在这里我将完全忽略代码,而聚焦于Stroboard(如果你使用xib,过程与此类似)。
在开始之前,为了你等够看到发生了什么需要对Xcode做一些微调。如果Assistant Editor不可见,打开它(View –> Assistant Editor –> Assistant Editors on Right) 并切换到预览(Preview)模式.
这样将在右侧面板看到storyboard的预览,默认的,它是为4英寸iPhone设置的。你可以点击预览底部的+图标,然后选择增加你所需要的其他设备(译者注:我没找到加号啊?),他们将在预览面板中平铺显示,所以,如果目前你还没有购入雷电显示器,那么是时候这么做了。
基本布局
默认的,Interface Builder 创建了一个正方形的“Any,Any”布局,换句话说,这是一个针对所有设备的普遍性布局。
我们将要通过创建一个固定边界的红色方块开始。拖动一个”UIVIew”到你的主视图,设置尺寸为200X200,放置在父视图中间,并将背景颜色改为红色。在Storyboard中,它看起来是这个样子:
好的,如果你在每个设备下预览(或在模拟器中运行应用),你将会发现他们看起来不一样:
为了解决这个问题,我们需要增加一些自动布局的约束。增加leading, trailing, top , bottom 约束各50像素。
再次运行,无论你使用哪种设备,红色方块都能够合适的放置(你可以在Resizable Simulator中调整设备尺寸,布局仍然能够正常工作)。
不同布局下变更约束
目前为止,这一切好像和早先版本iOS和Xcode没有什么关系。为了示范不同设备间布局的变化,我们将作出改变:即在横版屏幕下,红色方块充满整个屏幕。
为了做到这一点,我们需要改变之前增加约束的布局。在Attributes inspector视图的对象树中选中约束后,你将看到一个“Installed”的勾选框,和左侧一个小的+:
默认这个约束将在所有的布局中生效,我们要做的是为约束增加它们所适用的布局,通过点击+按钮,增加一个紧凑宽度,常规高度的布局:
当你增加了一个新的布局,约束将会被自动添加,通过取消选中”Installed”使其从默认布局中清除。
对其余的三个布局重复相同的动作,这时你已经从默认布局中清除掉了约束,你会看到这些约束从Interface Builder面板中消失,同时在视图树中也已经被置灰。
为查看约束在哪个size class里被激活,需要通过Interface Builder面板底部的选择器调整来进行。
一旦你切换了布局,你将会看到他们重新出现。
你在iPhone模拟器中再次运行应用,你会发现在竖屏状态下一切正常,但当切换到横屏,可怕的事情发生了-红色方块消失了,虽然伴随着漂亮的动画效果。这时因为在这种布局组合下没有约束存在,所以AutoLayout决定了让它消失。为了修复这个问题,我们需要为横屏方案增加约束。
在Interface Builder中,切换布局类为Any width, Compact height:
现在增加4个自动布局约束:leading, trailing, top 和 bottom ,每一个约束值置为0,现在每个约束被增加到Any, Compact 布局,而非默认:
再次运行应用,当模拟器被置为横屏状态下时,你会看到红色方块已经动态的充满屏幕。
在不同的布局下增加删除视图
相对于在不同布局下增加、删除、修改约束,同样的操作也适用于视图与控件。这样你将可以在横竖屏不同的方向下设计完全不同的界面;或者为不同的设备类型选择性的将界面分离。
为了说明这一点,我们将更新现在的视图:在横屏模式下增加一个白色方块。
切换到Any width, Any height,在界面上增加一个UIView,确保它是红色方块的同级视图,同时背景设为白色。
接下来,切换到Any width, Compact height,增加据四个边缘50像素的约束。
再次运行模拟器,你会发现在横屏下白色方块已经拥有正确的尺寸和位置,即使如此,其实横竖屏间的切换效果还可以更好一些:
这是因为不同的size class组合间的视图动画效果还未定义。
为了解决这个问题,切换至Compact width, Regular height,为中间的白色方块增加约束:宽高分别置为0,同时需要分别将这两个约束的优先级置为750,以避免尺寸约束(size constraints)与嵌入约束( inset constraints)之间的冲突。
这样就指定了竖屏至横屏动画的开始点,横屏至竖屏动画的结束点。因为开始与结束点的定义,白色方块实现了平滑的动画切换效果。
何去何从
通过使用size class与约束,使得在iOS8之前无法做到的在界面设计阶段实现可交互,在某种程度上成为可能。就像简单的管理设备旋转一样,你也可以创建一个通用性界面,那将使你的多设备适配工作容易的多。
另一个有意思的推论是我们已经掌握了为任意尺寸设备构建界面的工具:无论他是拥有大屏的iPhone6;或者Apple TV上;或者车载系统。也许我们期待已久的 Apple TV 开发工具也会不就面世。