iOS 11 自适应布局教程: 开始

原文:Adaptive Layout Tutorial in iOS 11: Getting Started
作者:József Vesza
译者:kmyhy

更新说明:本教程由 József Vesza 升级至 iOS 11、Xcode 9 和 Swift 4。原文作者是 Sam Davies。

对于 iOS app 设计人员来说,自适应布局的出现导致了巨大的变化。在设计你的 app,你现在只需要创建一个布局就能在所有设备上运行——不需要添加复杂的平台相关代码!

本教程介绍自适应布局。你会学习 universal 故事板、size 类、布局和字体定制、以及 IB 的改进(而这会带给你很大的便利)。

我们将为一个简单的天气 app 创建 UI —— 我们将从头开始创建。如果你不是一个自动布局爱好者,也毋庸担心;本教程第一部分会以 step-by-step 方式介绍用自动布局构建 UI。你会惊讶地发现,你完成这个工作不需写一行代码!

Universal 故事版

Universal 故事板是你迈向自适应布局的第一步。一个故事板可同时用于 iPad 和 iPhone。无需为每种设备准备单独的故事板——这个过程不但单调无味,而且容易导致错误。

打开 Xcode,选择 File\New\Project…。

选择 iOS\Application\Single View App 然后点击 Next:

iOS 11 自适应布局教程: 开始_第1张图片

Product Name 设为 AdaptiveWeather,Language 设为 Swift。所有选项都不勾选,然后点击 Next:

iOS 11 自适应布局教程: 开始_第2张图片

然后指定项目保存路径,在项目导航器中,你会看到:

iOS 11 自适应布局教程: 开始_第3张图片

Main.storyboard 可以用于所有的设备类型,不管屏幕尺寸多大。打开该故事板你会看到它有一个 view controller,当前尺寸为 iPhone7 的屏幕大小:

iOS 11 自适应布局教程: 开始_第4张图片

在 File 面板中,有个 Use Trait Variations 选项,允许在项目中开启这个新特性。打开故事板的文件面板,你会看到这个选项是这个样子的:

iOS 11 自适应布局教程: 开始_第5张图片

对于新建的 iOS 项目默认开启这个选项。你可以在将老项目的故事板转换到新项目中时,手动打开这个选项。

构建故事板

打开 Main.storyboard ,拖一个 Image View 到画布上。打开 Size 面板,将 x 设置为 37,y 设置为 20。width 设置为 300,Height 设置为 265。

iOS 11 自适应布局教程: 开始_第6张图片

然后拖一个 UIView 到 image view 下方。打开 Size 面板,将 x 设置为 37,y 设置为340,Width 设为 300,Height 设为 265:

iOS 11 自适应布局教程: 开始_第7张图片

选中这个 view,打开 Identity 面板,将 Label 设为 TextContainer。注意 Document 面板可能未显示——如果这样的话,点 Show 按钮显示它。 这给 view 取了一个名字,方便我们在 Document 窗口中找到它。这个 view 最终用于容纳城市和气温 label。

iOS 11 自适应布局教程: 开始_第8张图片

当我们从 Object Library 将视图拖到故事板中时,因为它们默认背景色都是白色,和 view controller 的 view 的颜色一样,会导致我们很难看得清它们的位置。要解决这个问题,先选中 view controller 的 view,打开属性面板,设置 background color 为 #4AABF7。

然后,选择 TextContainer ,将它的背景色设为 #3780BA。

最终 view controller 可能是这个样子:

iOS 11 自适应布局教程: 开始_第9张图片

这两个 view 现在直接作为 view controller 的 subview,接下来我们要为它们添加一些约束。

自适应布局

选中 image view 点击自动布局工具栏中的 Align。勾上 Horizontally in Container,确保值设为 0,然后点 Add 1 Constraint。

iOS 11 自适应布局教程: 开始_第10张图片

点击 Add New Constraints 按钮,添加上边距为 20:

iOS 11 自适应布局教程: 开始_第11张图片

点击 Add 1 Constraint 按钮。

前面添加的约束让 image view 顶部间距固定,并水平居中对齐。现在需要设置 image View 和 TextContainer 的间距。右键,从 image view 拖到 TextContainer,像这样:

iOS 11 自适应布局教程: 开始_第12张图片

将会弹出一个约束上下文菜单。选择 Vertical Spacing:

iOS 11 自适应布局教程: 开始_第13张图片

这个约束限制了 image view 底部到 TextContainer 顶部之间的间距。

选中 image view ,打开 Size 面板,你会看到:

iOS 11 自适应布局教程: 开始_第14张图片

你会看到有 3 个约束,你可以在这个 size 面板修改每个约束。点击 Bottom Space To:TextContainer 约束旁边的 Edit 按钮,你会看见一个对话框弹出,你可以修改约束的属性。将 Constant 设置为 20:

点击对话框外的地方,关闭对话框。

我们将 TextContainer 和 image view 之间的间距设置为 20,但我们还需要为这个视图的其它 3 边指定约束。

选中 TextContainer 点击 Add New Constraints 按钮。在 Sapcing to nearest neighbour 处,将相对于 superview 的左、右、下间距都设置为 0。 确认 Constrain to margins 未勾选,这会将 view 周围的内白去掉。

你可以参考下图所示的对话框:

iOS 11 自适应布局教程: 开始_第15张图片

点击 Add 3 Constraints,添加新的约束。这会将 TextContainer 的左边、右边和底边和 view controller 的 view 对齐。

现在,你的故事板看起来是这个样子:

iOS 11 自适应布局教程: 开始_第16张图片

注意有一个约束显示为橙色,而另一个约束显示为红色。这说明你的布局中存在问题。你可以让故事板自动修改视图的 frame 以满足这些约束。但如果你真的这样做,你的 image view 会被压缩为 0,0 大小。

这是因为 Image View 中没有内容——也就是说它当前的 intrinsic height/width 都是 0。如果没有为自动布局提供正确的宽高约束,那么视图的宽和高将由 intrisinc size 决定。

在项目导航器中,打开 Assets.xcassets。下载 cloud_images.zip 并解压缩。你将找到 3 个文件。将 3 个文件从 Finder 拖到 asset catalog 右手边的空白区域:

iOS 11 自适应布局教程: 开始_第17张图片

这将新建一个 image set,并自动将图片填充到正确的位置:

iOS 11 自适应布局教程: 开始_第18张图片

现在,你可以设置 image view 的 image 属性了。回到 Main.storyboard ,选中 image view。打开属性面板,将 Image 属性设为 cloud_small,将 Content Mode 设为 Aspect Fit :

iOS 11 自适应布局教程: 开始_第19张图片

你的故事板现在变成这个样子:

iOS 11 自适应布局教程: 开始_第20张图片

图片有了,好像每件东西都显示正常;view controller 自动对视图进行了重新布局,以适配新加的约束。

预览布局

通常,我们会在各种模拟器版本下运行 app——包括横屏和竖屏——以便测试新的 Universal 故事板。这个过程非常繁琐,但 Xcode 9 给我们一种更好的选择,就是新的 trait vairation 预览。

打开 Main.storyboard,找到画布下方的 View 按钮,点击它。这会弹出一个 trait 选择菜单:

在 Devices 这栏,选择 iPhone 4s(最右边的按钮)。

你会发现画布发生了变化,变成了 4 英寸屏:

iOS 11 自适应布局教程: 开始_第21张图片

要查看横屏效果,点击 trait 选择器中 Orientation 栏的 Landscape 按钮:

iOS 11 自适应布局教程: 开始_第22张图片

在调用不同模拟器方面,这是一种巨大的改进:通过点击按钮,你可以查看你的布局在不同设备上是否仍然显示。

注意到没有,在预览 iPhone 横屏时是不是有点不对劲?这是正常的——cloud 图片实在是太大李。。要解决这个问题,你需要给 image view 添加新约束。

回到故事板。右键,从 image view 拖到 view controller 的 view,新建一个约束。在上下文菜单中,选择 Equal Heights:

iOS 11 自适应布局教程: 开始_第23张图片

现在故事板中有好多约束都变红了。这是因为刚加的约束和已有约束发生了冲突,因为 image view 的高度不可能在和 view controller 的 view 相等的情况下,还保持之前的垂直边距对齐。

在 Document Outline 中选择新加的约束,打开属性面板,如果 First Item 不显示为 cloud_small.height,则请点击 First Item 下拉菜单中的 Reverse First and Second Item。

iOS 11 自适应布局教程: 开始_第24张图片

然后,将 Relation 设置为 Less Than or Equal,Multiplier 设为 0.4:

iOS 11 自适应布局教程: 开始_第25张图片

这是说,要么 cloud 图片的大小要么是图片的 intrinsic size,要么比这更小,为屏幕高度的 40%。

当你修改完约束,你会发现画布会自动刷新,变成:

iOS 11 自适应布局教程: 开始_第26张图片

完胜!

因为这是一个天气 app,你需要添加一些 Label 用于显示城市名称和当前气温。

填充 TextContainer 中的内容

在 Main.storyboard 中,返回 iPhone 7 竖屏,拖两个 Label 到 TextContainer 中,将它们按下图放置:

iOS 11 自适应布局教程: 开始_第27张图片

选择最上边的 label,点击 Align 和 Add New Constraints 按钮,让它水平居中,顶部边距 10:

iOS 11 自适应布局教程: 开始_第28张图片
iOS 11 自适应布局教程: 开始_第29张图片

然后,打开属性面板,将 Text 设为 Cupertino,Color 设为白色,字体设为: System,细,字号 150。

你可能发现 Text 当前是不完整的,这是因为 label 的 frame ——等会就解决它。

选中另一个 label,用 Align 和 Pin 菜单,让它水平居中,底部边距 10。在 size 面板中显示如下:

iOS 11 自适应布局教程: 开始_第30张图片

在属性面板中,将Text 设置为 28C,颜色白色,字体:System,Thin,字号 250。

在故事板中,Label 伸出了屏幕外边,并交叠起来了,这不是我们想要的。在解决这个问题之前,我们先来看一看 Trait。iPad Pro 9.7 吋屏下看起来效果倒是挺不错的:

iOS 11 自适应布局教程: 开始_第31张图片

当然,对于 iPhone 来说,这个字号未免大了一些:

iOS 11 自适应布局教程: 开始_第32张图片

在下一节,我们会来解决这些问题。

尺码

Universal 故事板是强大的——但你可能已经发行了,要在单一布局中适配所有屏幕是一个巨大的挑战。因此,自适应布局中另外几个工具将会非常有用。

自适应布局中的一个核心概念是尺码(size classes)。一个尺码是一种正确的用法,包含一定内容的 view 和 view controller 都能在给定的水平和垂直维度上进行显示。

Xcode 提供了两种尺码:Regular 和 Compact。尽管它们是相对于视图的物理空间而言,但也用于表示 view 的语义大小。

下表显示了不同设备和屏幕方向上的尺码定义:

iOS 11 自适应布局教程: 开始_第33张图片

这些尺码从设备传递到 app。但是,你可以在视图树的任意一级覆盖这些尺码。这在把 View controller 用在一个明显小于屏幕的容器中时候会非常有用。

你和尺码

尺码对于你和 app 设计中有什么意义?尽管你的 app 对尺码敏感,但你所构建的布局却没有明确的尺码——也就是说,你的布局保持相同的尺码。

在自适应布局的设计阶段,这就是关键。你应该构建一个基本布局,然后根据每个尺码进行定制。不要将每个尺码看成是完全独立的设计。将自适应布局看成一个层级结构,你可以将所有共享的设计放到父级,然后在子级的尺码中进行修改。

几乎不需要特别关注某种设备的布局设置。因为自适应布局的一个核心概念就是尺码和设备相关特性是分离的。也就是说支持自适应布局的 View 既可以用在一个全屏的 view controller 中,也可以用在一个嵌入的 view controller中,虽然外观上不同。

苹果的这种设计带来了一个好处,当苹果对设备的种类和特性进行扩展时,开发者和设计人员无需对 app 进行重构。

你可以利用尺码来定制 iPhone 的横屏布局,因为当前布局不太满足垂直空间有限的情况。

使用尺码

要使用 trait variations(特性变异),首先确认你的选择了一种高度为 Compact 的配置(例如 iPhone SE 横屏),然后点击 Trait 选择器右边的 Vary for Traits 按钮。

iOS 11 自适应布局教程: 开始_第34张图片

这里,你可以选择一个尺码,进行配置,并根据宽、高进行变异:

iOS 11 自适应布局教程: 开始_第35张图片

注意:这里的说法有点不一致。尺码总是和水平或垂直关联的。但是 IB 上使用的却是宽(width)和高(height)。这有一个简单的等意(宽=水平;高=垂直);它们是同一个概念。

当前布局在高度为 compact 时不正确。要解决这个,在 Vary for Traits 菜单中选择 Height:

iOS 11 自适应布局教程: 开始_第36张图片

你会发现底部的 bar 用蓝色进行了加亮。这表明,你当前正在某种特定的尺码布局下工作。

为了修改布局,你需要临时修改几个约束。用自动布局的术语来说,就是安装和卸载约束。如果在指定的尺码中,一个约束正在处于生效的状态,则叫做已安装,否则叫做已卸载,它不会发生作用。

选中 image view,打开 size 面板。你可以看一下哪些约束正在影响当前视图:

iOS 11 自适应布局教程: 开始_第37张图片

选中 Align Center X to: Superview 约束,单击它,按下 Delete 键从当前尺码中卸载该约束。这个约束会从故事版中小时,然后在 Document Outline 和 size 面板中,这条约束都会变灰。

iOS 11 自适应布局教程: 开始_第38张图片iOS 11 自适应布局教程: 开始_第39张图片

注意:要看见已经卸载的约束,必须在 size 面板中将 This Size Class 切换到 All。

在 size 面板中双击已卸载的约束以选中该约束。在最下面会多出一行,如下图所示:

iOS 11 自适应布局教程: 开始_第40张图片

这表明这个约束在基础布局中是已安装,但在高度为紧凑(Compact Height)的布局中(也就是当前正在编辑的布局)是未安装的。重复同样步骤,将 image view 其它 3 个约束卸载。在 Document Outline 和 size 面板中会是这个样子:

iOS 11 自适应布局教程: 开始_第41张图片
iOS 11 自适应布局教程: 开始_第42张图片

然后来为当前尺码添加所需的约束。用 Algin 和 Pin 菜单,添加垂直居中约束,并设置左边距为 10:

iOS 11 自适应布局教程: 开始_第43张图片
iOS 11 自适应布局教程: 开始_第44张图片

右键,从 image view 拖到 view controller 的 view,然后选择 Equal Widths。

打开image view 的 size 面板,双击 Equal Width to: Super view 约束。如果 First Item 不为 cloud_small.Width,则点击下拉列表中的 Reverse First and Second Item。然后将 Multiplier设为 0.45。

image view 在所有尺码下的约束都设置完了,但 TextContainer 还需要来看一看。我们需要修改它在当前尺码下的约束,将 label 移动到右边。

TextContainer 有几个内部约束,指定了 Label 的位置,它们原本工作得很好。但是,另外还有 3个外部约束——左、右、底边距——不正确。将这个视图的右下边对齐到父视图,首先需要卸载左边距约束。

在 Document Outline 中选择 TextContainer,将 Leading Space 约束从 size 模板中卸载。为了检查这个约束在 Compact Height 尺码中确实已经卸载,请在 Document Outline 中选择它,然后看一眼 size 面板:

iOS 11 自适应布局教程: 开始_第45张图片

现在添加两个约束到 TextContainer,让它的位置摆放正确。这个视图的高等于 superview 的 1/2 高,以及让它的上边距对齐。

理论上,你可以和之前一样,右键,从 TextContainer 拖到 view controller 的 view。但在实践中,我们经常很难选到这个视图,因为它上面还有其他内容。有一个简单的方法,你可以在 Document Outline 中完成同样的工作。

在 Document Outline 中,右键,从 TextContainer 拖到 view controller 的 view:

iOS 11 自适应布局教程: 开始_第46张图片

按住 Shift 键,连续选中 Vertical Spacing to Top Layout Guide 和 Equal Width。点击 Add Constraints:

iOS 11 自适应布局教程: 开始_第47张图片

打开 TextContainer 的 size 面板,将这两个新约束修改为:

  • Top Space to: Top Layout Guide 将 Constant 设为 0
  • Equal Width to: Superview 将 Multiplier 设为 0.5。注意同前面一样,有可能需要将 First Item 和 Second Item 进行颠倒。也就是双击约束,然后选择 Reverse First and Second Item。

故事板刷新后是这个样子:

iOS 11 自适应布局教程: 开始_第48张图片

布局的修改完成了;大功即将告成。还有一些问题,是调整字体大小——我们放在下一节进行。

自适应字体

在 TextContainer 中,当前字体在 iPad 常规尺码上显示效果非常好,但对于紧凑尺码这个字体太大了。别担心——我们也可以在自己的尺码中修改字体大小。

注意:和布局的重定义不同,字体改变只会在基本布局上进行。改变字体不需要在 IB 中覆盖当前尺码的字体设置。它用的是后面所说的办法。

点击 Trait 选择器菜单中的 Down Varying 按钮。这个 bar 会变成灰色,表示你回到了基本布局。

选中 Cupertino 标签,打开属性面板。点击 Font 左边的 + 。

这会显示一个菜单,显示一个尺码组合的列表供你选择。选择 Width 为 Compact,Height 为 Any:

iOS 11 自适应布局教程: 开始_第49张图片

这会增加第二个字体选择框,并显示出是那个尺码所用。修改字号大小为 90:

iOS 11 自适应布局教程: 开始_第50张图片

然后,选择气温标签,重复同上步骤,这次将 Compact width 和 Any Height 尺码下的字号改为 150。

修改生效后的 IB 显示为这个样子:

iOS 11 自适应布局教程: 开始_第51张图片

好,看起来好多了,但 Cupertino 标签被剪切了。你可以捣鼓一下字号直到它完美,但这种方法一点也不灵活。Cupertino 是有点长,但 Washington,D.C. 更长—— Kleinfeltersville,PA 更更长!这个怎么弄?

再一次,自动布局来了。你只需要将两个 Label 的宽度限制在 TextContainer 的宽度就行了。右键,从Cupertino 标签拖到 TextContainer,然后选择 Equal Widths。

在气温标签上重复同样步骤。画布刷新后是这个样子:

iOS 11 自适应布局教程: 开始_第52张图片

呃,文本截断其实不是你想要的。这是 Label 在内容太长超出有效空间之后的默认行为。当然,有一种方法可以自动根据内容调整字号大小。

选中 Cupertino 标签,打开属性面板。将 AutoShrink 修改为 Minimum Font Scale 然后将值设为 0.5。同时将文本对齐设置为居中。属性面板中是这个样子:

iOS 11 自适应布局教程: 开始_第53张图片

对气温 label 重复同样步骤。

看一下 IB 中的画布,iPhone 布局现在看起来会好一点:

iOS 11 自适应布局教程: 开始_第54张图片

在预览编辑器中看起来不错,但是是时候 Build & run 来看看是否正确了。iPhone 屏幕看起来在每种尺码上都正确了:

iOS 11 自适应布局教程: 开始_第55张图片
iOS 11 自适应布局教程: 开始_第56张图片

恭喜你,你已经学习了基本的自适应布局技术!

结束

完成后的示例项目从这里下载。

花点时间看一下你编写的这个 app(或者下载下来的完成后的项目)。它所特别的地方在于,它只用李一个故事版文件,无论在上面设备、什么屏幕方向上都能正常显示。

自适应布局必然是大势之所趋。其中最能说服人的一点莫过于,这种布局哪怕是对于未来的设备也能够显示正确,而不需要发布新的版本。

本教程最终得出结论,作为一个开发者,你需要改变 app 设计的方式。和使用基于像素方式的布局不同,你应该考虑 UI 元素和屏幕之间的关系。

如果你想学习更多关于 Adaptive Layout 的内容,请阅读我们的自适应布局视频教程系列,它会带你从初学者变成自适应布局的高手!你也可以看看这两个 WWDC 2016 “构建自适应 app” 的视频:Part 1,和 Part 2 。

同时,如果你有任何问题或建议,请在下面留言!

你可能感兴趣的:(iPhone开发)