Swift自适应布局(Adaptive Layout)教程(一)

通用的Storyboard

通用的stroyboard文件是通向自适应布局光明大道的第一步。在一个storyboard文件中适配iPad和iPhone的布局在iOS8中已不再是梦想。我们不必再为不同尺寸的Apple移动设备创建不同的storyboard文件,不用再苦逼的同步若干个storyboard文件中的内容。这真是一件美好的事情。

我们打开Xcode,新建一个项目:

图片

选择iOS\Application\Single View Application创建一个单视图应用:

图片

设置项目名称AdaptiveWeather,语言选择Swift,设备选择Universal

图片

创建好项目后,我们在项目目录结构中可以看到只存在一个storyboard文件:

图片

Main.storyboard文件就是一个通用的storyboard文件,它可以适配目前所有屏幕尺寸的Apple移动设备。打开该文件,同学们会看到一个View Controller,以及一个我们不太熟悉的界面尺寸:

图片

同学们不要吃惊,没错,你们看到的就是一个简单的、有点大的正方形!大伙都知道,在上一个版本的Xcode中,storyboard里的屏幕尺寸都对应着我们所选的目标设备的尺寸,但是这样无法让我们达到“用一个storyboard搞定所有设备”的宏伟目标。所以在iOS8中,Apple将storyboard中屏幕的尺寸进行了抽象处理,也就是说我们看到的这个正方形是一个抽象的屏幕尺寸。

我们接着往下走,选中Main.storyboard文件,然后在右侧工具栏中选择File Inspector页签,然后勾选Use Size Classes选项:

图片

在新的iOS8项目中,该选项默认是勾选的。但当你使用老版本的项目创建新的storyboard文件时就需要你手动进行勾选了。

设置你的Storyboard文件

首先,我们打开Main.storyboard文件,从组件库(Object Library)中选择Image View拖拽到View Controller中。选中刚刚拖入的Image View,在右侧工具栏选择Size Inspector页签,设置X坐标为150,Y坐标为20,为300,为265。

然后再拖入一个View组件,设置X坐标为150,Y坐标为315,为300,为265。

选择你刚才拖入的View,在右侧工具栏中选择Identity Inspector页签,在Document面板中的Label属性输入框中输入TextContainer。这个属性的作用就是给View起一个名字,方便我们辨认。这里要注意一下,Document面板有可能是隐藏的,我们需要点击它后面的 Show按钮来显示它。我们拖入的这个View最后是显示城市和温度Label的容器。

图片

完成上面的设置后,同学们可能会发现刚才拖入的View貌似看不到,这是因为它的背景色和View Controller的背景色是相同的,都是白色,所以我们不太容易辨别。我们来解决这个问题,选中View Controller的View,然后在右侧工具栏中选择Attribute Inspector页签,设置背景色为 红:74,绿:171,蓝:247。然后再选择TextContainer,就是我们拖入的View,设置背景色为 红:55,绿:128,蓝:186。此时Main.storyboard文件中应该是这番景象:

图片

到目前为止,我们在View Controller中添加了两个组件Image View和View,这也是仅有的两个组件,接下来我们就要给它们添加一些布局约束了。

添加布局约束

选择image view,点击底部自动布局工具栏中的Align按钮,勾选Horizontal Center in Container选项,将后面的值设置为0,点击 Add 1 Constraint按钮添加第一个约束。

图片

这个约束的意思是让image view在它的容器(View Controller的View)中保持居中。

然后再点击底部自动布局工具栏中的Pin按钮,添加一个image view顶部与容器顶部间距的约束,我们设置为0:

图片

上面这两个约束使image view处于容器居中的位置,并且它的顶部与容器顶部有一个固定的间距。现在我们需要添加image view和text container view之间的约束。同学们先选中image view,然后按住Ctrl键和鼠标左键,从image view往text container view移动鼠标:

图片

松开鼠标左键后会弹出一个约束菜单,我们选择Vertical Spacing

图片

这个约束决定了image view底部和text container view顶部之间的距离。

现在选中image view然后点击右侧工具栏中的Size Inspector页签,同学们会发现这里在Xcode6中和之前的Xcode版本有所不同:

图片

你会看到之前添加的三个布局约束,你可以在Size Inspector中很方便的修改这些布局约束。比如点击Bottom Space To: TextContainer约束后的 Edit按钮,会弹出约束属性编辑框,我们让Constant的值等于20:

图片

然后点击该弹出框之外的任意地方关闭该弹出框。

你先已经将TextContainer view顶部与image view底部的间距调整到了20,我们还需要添加TextContainer view另外三个边的间距约束。

继续选择TextContainer view,点击底部的Pin按钮弹出 Add New Constraints窗口,在 Spacing to nearest neighbor面板中设置左、右、底部的约束,将值设置为0,然后点击Add 3 Constraints按钮添加约束。这里要注意的是,在设置约束时要将 Constrain to margins选项的勾去掉,这样可以避免TextContainer view产生内边距:

图片

这三个约束会让TextContainer view的左、右、底部三个边与容器的左、右、底部的间距始终为0。

现在Main.storyboard中应该是这番景象:

图片

此时同学们应该会注意到在view上有几个橘黄色的约束线,这意味着还有一些约束上的问题需要我们注意。不过在运行时storyboard会自动更新view的大小来满足它与容器的约束条件。我们也可以点击底部 Resolve Auto Layout Issues 按钮,在弹出框中选择 All Views in View Controller/Update Frames 来修复提示的约束问题,但是如果我们这样做,那么image view的尺寸就会压缩成零,也就是会看不到image view。

这是因为我们的image view还有没有任何内容,但是它有一个缺省的高和宽,并且值为0。进行自动布局的时候,如果被约束的view没有实际的高和宽,那么会依照缺省的高和宽来满足约束条件。

我们接着学习,在项目结构中打开 Images.xcassets ,然后点击左下角的 +号,在弹出菜单中选择 New Image Set

图片

双击左上角的 Image 标题将其改为 cloud

图片

我们刚才新建的这个image set其实就是若干图片文件的一个集合,其中的每一个图片都会对应一个特定的应用场景,也就是针对与不同分辨率的Apple移动设备。比如说,一个图片集合可能会包含针对非视网膜、视网膜、视网膜高清三种分辨率的图片。自从Xcode中的资源库与UIKit完美结合后,在代码中引入图片时我们只需要写图片的名称,程序在运行时会根据当前运行的设备自动选择对应分辨率的图片。

注意:如果你以前使用过通过资源库管理图片,那么你可能会发现在Xcode6中会有所不同。那就是3x图片是怎么回事?

这个新的分片率是专为iPhone 6 Plus提供的。这意味着每一个点是由3个像素点组成,也就是说3x的图片比1x图片的像素多9倍。

目前你的图片集合中还是空的,同学们可以在这里下载需要的图片cloud_images.zip ,然后将图片拖入刚才创建的名为cloud的图片集合中,将 cloud_small.png图片拖到 1x图片区域:

图片

由于我们的图片背景颜色是透明的,所以在图片集合中看到的都是白色的图片。你可以选中某一个图片,然后按下空格键来预览图片。比如选中 1x 图片,按下空格:

图片

现在将 cloud_small@2x.png 图片拖至 2x 图片区域,将 cloud_small@3x.png 图片拖至 3x 图片区域。和之前情况一样,我们看到的只是白色的图片,但我们可以通过空格键来预览图片集合中的图片。

现在你就可以在image view中设置图片了。我们回到 Main.storyboard 中,选中image view,在右侧工具栏中选择 Attribute Inspector 页签,将 Image View 面板中的 Image 属性设置为 cloud,然后将 View 面板中的 Mode 属性设置为 Aspect Fit

图片

现在你的Main.storyboard中应该是这番景象:

图片

我们看到storyboard中一直有橘黄色的约束提示,是时候让我们来修复它们了。首先选中view controller的view:

图片

然后点击底部的 Resolve Auto Layout Issues 按钮,在弹出菜单的 All Views in View Controller 面板中选择 Update Frames

图片

这时,storyboard会自动根据约束条件重新计算view的大小以满足约束:

图片

预览助手编辑器(Preview Assistant Editor)

一般情况下,在这个时候我们应该会在iPad、iPhone4s、iPhone5s、iPhone6、iPhone6 Plus这几个不同尺寸的设备上编译运行程序,以便测试通用的storyboard是否能在不同尺寸的设备上正确的自适应。但这确实是个体力活,一遍一遍的更改设备、编译、运行,多么苦逼。但上天总是会眷顾我们这些苦逼的程序员,Xcode6提供了Preview Assistant Editor,能在一个界面上显示出不同尺寸设备的程序运行情况,是否有问题一目了然。

我们打开 Main.storyboard ,然后选择 View\Assistant Editor\Show Assistant Editor ,这时编辑区会分隔为两部分。再点击顶部导航栏中的 Automatic ,在弹出菜单中选择 Preview ,最后选择 Main.storyboard (Preview)

图片

现在在 Assistant Editor 区域会显示一个4寸的界面:

图片

我们还可以点击预览界面底部,名字(比如图中的iPhone 4-inch)旁边的地方让屏幕翻转为横屏:

图片

这无疑是针对检查不同尺寸设备的自适应情况的一项重大改进,但还远远不止于此!点击预览界面左下角的 + 按钮,会弹出当前storyboard文件支持的各种尺寸的设备,可供我们预览:

图片

分别选择iPhone 5.5-inch和iPad,此时我们在预览界面就可以同时显示三种尺寸的屏幕:

图片

此时同学们是否注意到4寸的横屏显示有点别扭呢?没错,它的那朵元太大了,我们可以通过对image view添加其他的约束条件来改善这个问题。

回到 Main.storyboard ,选择image view,然后按住 Ctrl建和鼠标左键,拖动鼠标到View Controller的View上,松开鼠标后会弹出一个菜单,我们选择 Equal Heights

图片

这时会出现一些红色的约束提示,这是因为我们刚才加的这个约束条件与之前加过的约束条件有冲突。因为之前我们添加过image view和TextContainer view之间的垂直间距(Vertical Margins)约束,所以image view的高度不可能等于它容器(View Controller的View)的高度。

让我们来修复该问题,首先在storyboard的结构目录中选择我们刚才添加的 Equal Heights 约束,然后选择右侧工具栏中的 Attribute Inspect 页签,如果 First Item 属性不是 cloud.Height ,那么在下拉菜单中选择 Reverse First and Second Item 这一项让 First Item 的值成为 cloud.Height

图片

接下来将 Relation 属性的值设置为 Less Than or Equal ,将 Multiplier 的值设置为 0.4

图片

这一系列设置的作用是让cloud这张图片的高度要么等于它自身的高度,要么等于屏幕高度的40%,最后呈现的效果选择这两者中较小的一个高度。

现在你应该注意到了在预览面板中,4寸的横屏显示即时的对你刚才的约束改动做出了响应:

图片

你看看其他尺寸的预览自动更新了么?答案那是必须的,所以说 Preview Assistant Editor 确实是一项重大改进,是程序员和设计人员的福音!

由于本文的示例是一个天气应用,所以光有天气图标不行,我们还得加上城市和温度才行。

未完待续……

原文地址:Beginning Adaptive Layout Tutorial

分享到: