iOS发展 ---- 至iPhone 6自适应布局设计 Auto Layout
Apple从iOS 6增加了Auto Layout后開始就比較委婉的開始鼓舞、建议开发人员使用自适应布局,可是到眼下为止,我感觉大多数开发人员一直在回避这个问题,无论是不是因为历史原因造成的,至少他们在心底还坚守着固定布局的老传统思想。
随着iPhone6、iPhone6 Plus的到来,使用自适应布局更是迫在眉睫的事,固定布局的老传统思想脆弱的不堪一击。如今的iPhone有4种尺寸。假设算上iPad,如今Apple的iOS设备有5种尺寸。
我们在准备使用自适应布局设计应用界面之前。能够把这5种尺寸划分为3种分辨率和屏幕方向。这样在设计时分类会更加清晰一些。
我们先来看一张自适应布局的效果图:
当你们学习完这篇文章后,你们应该会比較自如的使用 storyboard、constaints、size classes 这三个Apple在Xcode里提供的工具,去探索和构建巧妙的自适应布局。
Storyboards
在Xcode中,storyboard是一个能够让我们相应用界面进行可视化布局的工具,你首先能够在storyboard文件里看到一个或若干个iOS设备屏幕大小的布局区,然后你能够从组件库(Object Library)中拖拽组件到屏幕布局区中进行布局(比方button、图片、文本框、labels等)。你还能够定义屏幕布局区之间的连接关系。
用Xcode的术语来说。人们能够看到、触碰到或以其它方式(button、图片、文本框、labels等)进行交互的用户界面被称为views。屏幕中包括和管理这些views的容器称为view controller。
当我们在storyboard中加入一个view controller后,我们所示并非一个我们熟知的屏幕尺寸。而是一个600X600的正方形:
从上图我们能够非常明显的看出。storyboard中显示的屏幕尺寸不是实际设备的尺寸。Apple这样做的目的是将屏幕尺寸进行了抽象化,也就是说你能够将这个正方形的屏幕看成iphone4的屏幕,也能够将它看成iphone6的屏幕。
模拟器的尺寸
当你习惯了600X600的屏幕后。你可能会用着非常爽,可是有些时候,我们也须要将它改成实际的屏幕尺寸来设计一些东西。
我们能够非常方便的在Xcode中改变view controller的模拟屏幕尺寸和屏幕方向:
布局约束
介绍布局约束的最好、最直观的方法就是向你们展示一个演示样例。
首先我们将storyboard中的屏幕布局区域的尺寸调整为iphone5s的尺寸,也就是4寸屏幕,然后加入两个正方形的view,并排放置在屏幕顶部,一个设置为蓝色,一个设置为粉色。
我们选择iPhone5s模拟器设备并编译执行应用,能够看到一蓝一粉这两个方块依照我们设定的那样杵在竖屏方向的屏幕上,没有问题。
当我们把设备调整为横屏时。这两个方块像拥护党一样拥护着他们的坐标位置,所以在横屏的时候看着就不是那么完美:
我们再将模拟器改为iPhone6,然后编译执行。此时在竖屏的时候就已经感觉无法再爱了。
这两个方块并没有依照我们设置或设想的那样在屏幕顶部中间,而是偏向了左边,在右边有一块留白区域。
这是就是没有布局约束而导致的,蓝色粉色方块的大小、坐标位置都是固定的,都是在4寸屏幕的參照下设置的。不论在哪种尺寸的屏幕下。它们都在固定的那个坐标位置和固定的大小。所以就会出现上面的情况。
那么接下来让我们给这两个方块加入一些布局约束。再看看会有什么奇妙的事情发生。
页边间距约束(Leading and Trailing space)
页边间距约束分前部间距约束(Leading space constaint)和尾部间距约束(Trailing space constaint)。从屏幕上说就是左边距和右边距。我们给蓝色方块加入左边距约束,其值设置为10,给粉色方块设置右边距约束,其值也设置为10。
我们再次在iPhone5s模拟器中执行应用,当横屏时蓝色方块被左边距约束拉到了屏幕左边,粉色方块被右边距约束拉到了屏幕右边。
水平间距约束(Horizontal space constaint)
给蓝色方块和粉色方块加入水平间距约束,其值设置为10。这个约束会使这两个方块之间的距离永远约束为10。
我们再来执行应用。如今横屏时两个方块之间的间距、它们与屏幕边缘的间距都和竖屏时显示的一样了。可是当中粉色方块为了满足水平间距约束自行添加了方块的宽度,变成了长方形。简直是一仅仅老鼠坏了一锅汤有木有。
从上面这个效果我们能够得知,除非我们特别限制了view的尺寸。否则的话iOS会为满足布局约束而改变view的尺寸,也就是保持一个自然的尺寸。
等宽约束(Equal widths constaint)
我们给这两个方块加入一个等宽约束来改善上面的情况。
再次执行应用,如今在横屏时因为等宽约束的作用,两个方块的宽度保持了一致。我们已经很接近完美了。
方向比例约束(Aspect ratio constaint)
从上面的执行情况来看各个约束都工作正常,但唯一不足的是本来在竖屏是两个正方形方块,在横屏时缺变成了长方形方块。由范爷变成了凤姐这是人类无法接受的。
我们给这两个方块加入方向比例约束来解决问题。这个约束使方块在满足其它约束的前提下始终保持高和宽的比例同样。
所以在横屏时就会以方块的宽度为比例标准,将高度的比例改为宽度的比例。
用iPhone5s模拟器编译执行应用,如今在横屏状态下两个正方形方块完美的呈如今我们眼前。
我们在iPhone6模拟器上再编译执行应用,从以下的图中我们能够非常清晰的看到加入约束之前和之后的变化。布局约束依据多出的空间大小将方块放大到合适的尺寸以满足约束。
实践布局约束
到眼下为止。你们已经看到布局约束奇妙的作用和效果。是时候让你们在你们自己的storyboard文件里加入布局约束了。
熟练布局约束最好的方法就是多练习。从加入少量的布局约束開始,一步步达到自己想要的效果。
另外有一点,我始终不觉得加入过多的布局约束会相应用的性能产生影响。可是我们也不能滥用约束布局,好钢要用在刀刃上。我们尽可能用最节俭的约束布局达到我们想要的效果。
加入布局约束的方式
这里向大家介绍三种在storyboard中加入约束的方式:
1.底部布局约束button
这样的方式可能是最简单直观的一种方式,在屏幕上选择一个或多个对象,然后点击底部的布局约束button加入一个或多个须要的约束。
它的优点是能够直观的看到当前选择的对象已经加入了该类中的那些约束。
假设你指选择了一个对象想要加入某个约束,但发现该约束是不可选的,那么就意味着这个约束是适用于两个以上对象的约束。
2.按住Control键拖拽鼠标
你也能够选择一个对象,然后按住Control键和鼠标左键,拖拽鼠标到还有一个对象(容器对象,也就是父对象或者选中对象自己)。松开鼠标后会弹出适用的约束菜单。你能够选择约束进行加入。
这是我偏爱的一种方式,由于它比上面那种方式来的快多了。
3.菜单/绑定快捷键
你也能够通过菜单选项editor —> pin给一个或多个对象加入布局约束。
这是效率最低的一种方式。假设你发现有些约束你会一遍遍的重复加入。那么你就能够给该约束绑定一个快捷键来提高效率。
检查和编辑已加入的布局约束
检查约束最简单的方式就是选中一个对象,然后打开右側工具栏。选择Size Inspector面板。
或者在storyboard界面左側的结构树中查看约束。
通过这两种方式,你都能够选择某个约束,然后编辑它。
移除布局约束
布局约束能够加入自然也就能够删除。
选中某个约束使其高亮显示,然后按下Delete键移除该约束。
假设想移除某个对象上全部的约束,有一个快捷的方式。选择该对象。然后在底部点击Resolve Auto Layout Issuesbutton,选择Clear Constaints。
布局出现的问题和冲突
我们在加入约束时。常常伴随有警告或者错误出现。
尽管有些警告是由于我们还没有加入完约束出现的,当我们加入完我们设想的约束后警告就会自然消失。但大多数的警告还是指明我们的约束确实存在问题,须要我们修复。
查看警告或错误最方便的方式就是在storyboard左側的结构树中,在view controller的右边会出现一个红色或黄色的小图标。向我们指明这里存在问题:
错误摆放view的警告
view位置的错误摆放是一个非经常见的警告。当一个view没有摆放在约束规定的位置的时候,会出现该警告。
这些问题会在你切换不同设备的模拟器或鼠标不小心移动了某个对象时出现。
选中一个错误摆放的对象,在屏幕上会出现布局约束给你提示的正确的摆放位置。
点击左側出现的黄色警告图片。会弹出一个菜单。你能够选择让Xcode改变约束,以适应当前该对象的位置,但通常情况下我们都选择让Xcode将该对象移动到约束规定的位置。
缺少布局约束的错误
我们回到早些时候的演示样例中。
这时候我们没有给方块加入Y坐标位置的约束。
在执行时没有问题,由于iOS会如果方块的位置就是我们在storyboard中摆放的那个位置。可是Xcode会提示我们一个缺失约束的错误,为了避免意外发生(更换设备尺寸),我还是要依据Xcode的提示加入缺失的约束。
我们给这两个方块加入一个top space to to layout guide约束使方块的位置更加清晰,并消除Xcode的错误提示。
自适应布局的布局约束自然是好东西。但也不是万能的,有时候我们也须要使用最主要的布局。所以使用size classes将它们两者结合起来才干碰撞出更有激情的火花。
Size Classes并不代表真正的尺寸,而是我们从感官上感觉尺寸的种类。通过这样的种类的组合。表示出不同屏幕尺寸设备的横屏及竖屏。
我们在给storyboard中的对象加入约束时能够选择给某一个size class加入约束,所以在你选择特定的size class时。仅仅能看到你加入的仅仅适用于该size class的约束。
这些特性能使我们有效的在不同的设备和屏幕方向中定义、设计不同的用户界面。
Size Classes中的高和宽
Size Classes为高和宽分别提供了三种类型:紧凑型(compact)、普通型(regular)、随意型(any)。用这三种高和宽的类型就能够组合出9种size class,来表示不同的设备屏幕。
在实际运用中,我们发现并非全部的尺寸都能在Size Classes中找到明白的组合(比方没有组合能够明白表示iPhone6 Plus的竖屏。iPad的横竖屏也不好区分),可是我们能够使用表示这个尺寸范围的组合。
比方我们能够用Compact Width | Regular Height来表示iPhone6 Plus的竖屏。
接下来还是用一个活生生的演示样例来向大家介绍Size Classes。
我们的目标
这个演示样例是实现Instagram的一个具体信息页面。并让它自适应更大的屏幕尺寸。在竖屏和横屏中都展现出最合适的布局。
我们的目标是让布局自适应iPhone6的屏幕(这里须要注意一下,我所说的自适应是指图片、文字信息的布局排版,对于个人信息的头像不会依据布局的变化而变化)。在竖屏中各个信息依照堆栈方式从上到下布局,在横屏时各元素依照大小进行有序排列,而不再是堆栈的方式:
给通用的size class加入约束
在这个演示样例中,我们不会像上个演示样例那样使用模拟器的实际尺寸来设计布局。我们使用Size Classes提供的抽象的屏幕尺寸,这里我们先使用通用的尺寸来设计布局,也就是w Any | h Any尺寸。我们要注意的是,在这个尺寸下加入的view或者约束必须是一些公用的,也就是说在不论什么尺寸,不论什么屏幕方向的情况下都适用的。
这些约束包含:
除了之前介绍过的页边间距约束、水平间距约束、等高等宽约束、方向比例约束外还有顶部、底部间距约束。
加入完上述的view和约束后,storyboard里应该是这番景象:
这里要注意一下,眼下这个界面的布局还有非常多关键点须要考虑横屏和竖屏的布局,可是这些工作不会在w Any | h Any尺寸下进行。大伙接着往下看。
为iPhone的竖屏加入布局约束
如今在Size Classes选择器中选择w Compact | h Regular尺寸。这个size class适用于全部iPhone设备的竖屏界面,不论尺寸是多少。
当你在Size Classes选择器中选择某一个size class后,storyboard 中的view controller会实时的反映出你改变后的尺寸大小。
如今你就能够为iPhone的竖屏状态又一次设计view的位置和加入新的布局约束了。
下图中说明了我在竖屏状态下加入的约束:
我的storyboard中看起来是这种:
在这个阶段,你能够在3.5、4、4.7、5.5这几个尺寸的模拟器中编译执行应用,在竖屏状态下看看它们的执行情况。虽然在横屏状态表现的还非常糟糕。
这里要注意的是我们并未定义图片的宽度,我们仅仅是给图片加入了相对父容器的左右边间距,并将其值设为了0。所以当屏幕尺寸增大的时候图片的宽度在布局约束的作用下也会添加。这时又由于我们给图片加入了高宽比例约束,所以图片的高度也会随之添加。
为iPhone的横屏加入布局约束
打开Size Classes选择器。选择w Any | h Compact,这个size class适用于不论什么一个尺寸的横屏状态。我们将在这个size class下设计我们希望在iPhone横屏时显示的用户界面。
此时图片的顶部、左側、底部都加入了相对于父容器的边界约束。
在显示评论的label上加入了右側边界约束。
当设备横屏时。图片在布局约束的作用下移到了左側。个人信息label和评论label在约束的作用下被挤到了右側,而且评论label的高度添加,宽度降低。
如今来看看我的storyboard中显示的内容。大家注意左側的对象结构树中有非常多个约束,可是有些是灰色的。
那是由于这些灰色的约束在当前的size class下是禁用的,或者说不适用、不起作用。那些是竖屏时用到的约束。
如今在storyboard中切换size class时布局也会随之变化,更新很及时和平滑。
我们在模拟器中编译执行应用,切换横竖屏,能够看到布局切换的效果,过度很自然平滑。
为了能让大家看清楚布局变化过度的细节,我放慢了这个git动画。大家注意,在布局变化时屏幕上的组件有一个层级关系,从该演示样例中我们能够看到图片view的层级高于个人信息label和评论label。
所以我们在设计布局的时候就要考虑怎样给view分层,包含在普通布局中不会被覆盖的view。这是一个细节问题。
屏幕预览助手编辑器
Xcode6中还有一个值得关注的功能是屏幕预览助手。它能够避免你一遍遍的在不同屏幕尺寸的模拟器中编译执行应用来检查布局的正确与否。你能够在屏幕预览编辑器中加入一个或多个你想查看的屏幕尺寸,并能够让他们呈现横屏或竖屏的状态。
当然它也不是非常完美(由于在预览时导航栏的颜色会丢失)。可是切换Double Length Pseudolanguage选项非常方便。便于你检查问题。
从上图中大家能够看到我在屏幕预览编辑器中显示了3.5寸屏幕的横屏和4寸屏幕的竖屏。总体布局没有问题,可是当选择Double Length Pseudolanguage使label中的文字都添加一倍时,问题就出现了,个人信息和评论的label长度没有自适应。
为iPad布局加入约束
如今我们将Sizae Classes调整为w Regular | h Regular,这个size class表示了iPad的横屏和竖屏大小。
和往常一样。我们先调整图片和各个label的位置及大小,调整惬意后,再加入相关的约束。在iPad布局中我打算将图片的尺寸设置为固定尺寸(不像iPhone中那样随着横屏和竖屏改变图片的尺寸),并将个人信息和评论label紧跟在图片以下。
我的storyboard如今看起来是这种:
以往。我们都是在特定的size class中加入相关的约束,但在iPad布局中。我们不只只加入一些约束。
由于在iPad布局中有非常大的空余空间,所以我们不仅仅是又一次排列一下组件的位置和大小,我们还要加入一些其它的组件。在这个演示样例中,我们再加入两个图片view(分别表示当前显示图片的上一张图片和下一张图片)。
再来看看我的storyboard:
我们不须要对这两个图片手动的设置高宽。而是给它们设置对于主显示图片的相对高宽就可以。
这样做的优点是当主显示图片的尺寸更改时,我们不须要自己手动计算和更改这两个图片的尺寸,相对高宽会自己主动针对主显示图片的尺寸调整这两个图片的尺寸。
我没有制作在iPad上执行的gif动画。但这里有iPad横屏竖屏的执行图片,大家能够看看:
使用布局视图和间距视图
眼下Xcode提供的布局约束能够满足大部分的布局需求,可是有些场景下须要变通的使用约束才干达到我们想要的效果。
布局视图演示样例
通过Xcode提供的约束,我们能够非常easy设置组件与view controller view的边缘的间距。也能够非常easy的让组件在view controller view中水平居中显示和垂直居中显示。可是却不太easy设置组件与view controller view的水平中线或垂直中线的间距。
像这样:
以下向大家介绍两种实现该需求的方法。首先我们先加入一个view,背景色设置为透明,让它在屏幕中垂直居中显示。它作为该需求中组件的父容器,由于父容器在屏幕中是垂直居中的,所以能够给组件加入相对于父容器的Center X约束,就能够达到我们的需求了:
可是通过上述的方式未免会使我们的布局的层级关系太过复杂,我更希望布局比較扁平一些,不须要太多的层级关系。由于上述方法中的容器view主要是用于布局使用。所以这样的view我称之为布局视图。
我们来改进一下方法。首先也是在view controller view中加入一个布局视图。我习惯将高度设置为20(这个值随个人喜好或实际情况而定),然后将它和屏幕的顶部、左側、右側的间距设为0,这种话这个布局视图就和状态栏重合了。我们将这个布局视图设置一个深一点的颜色,然后将它的hidden属性设置为true,这样布局视图的颜色就会变浅。也不太会影响我们的布局,并且在应用执行时是不会显示该视图的。
如今我们的组件就能够设置相对于布局视图的Center X约束来实现我们的需求了。
间隔视图演示样例
之前我们学习了怎样使用约束设置视图和视图边缘的间距,而且当屏幕尺寸添加时视图也会对应的改变大小,但它们的间距不会改变。
可是假设我们希望当屏幕添加尺寸时。视图的大小保持不变,仅仅是添加间距呢?
从理论上讲,实现该需求可能能够使用类似等宽这种约束,可是现实往往的是骨干感的。
这时我们就须要间距视图出场了,和布局视图一样,间距视图能够设置一个深一点的颜色,hidden属性要设置为true。
我们在每一个视图与视图间距之间加入一个间距视图,设置每一个视图与相邻间距视图的边缘间距约束,然后给全部的间距视图加入相对于view controller view的等宽约束。设置合适的比例就可以。
id=9978&action=article