智能手机发展到今天,屏幕尺寸变的愈来愈多,iPhone从最初的3.5寸屏幕,到后来推出的4寸屏,直到苹果推出iPhone 6 和 iPhone 6Plus,也宣告着苹果阵营被完全攻破,进入了屏幕尺寸碎片化的时代。只为某一个屏幕尺寸设计的日子已经不在存在。为了适配全部的屏幕,设计师必须考虑各类屏幕尺寸。可是又不可能为每一个尺寸都设计一遍。那么咱们又该如何面对屏幕碎片化的困境?html
图1,图片来自:HTTP://WWW.PAINTCODEAPP.COM/NEWS/ULTIMATE-GUIDE-TO-IPHONE-RESOLUTIONSios
苹果给出的答案是AutoLayout。让你能用一个设计来适配全部屏幕,理论上讲从iPhone4适配到iPad pro均可以。它但愿你忘记某个具体的尺寸。实际上你能够随意拖出一个任意尺寸的画布进行设计,标注好后就能够交给工程师开发。app
首先咱们先看一下,苹果的开发软件Xcode上是让你怎么进行页面布局的。布局
图2,XCODE.STORYBOARDspa
中间那块白色的正方形就是画布,若是你是使用storyboard布局的话(iOS的布局方式有不少种,storyboard只是其中一种,我在后面会讲),你能够将你设计好的控件放到这个画布上去,根据你标注的尺寸定义好它们的位置关系,接下来AutoLayout就会自动适配各个屏幕了。听上去好像很神奇。设计
有些人会有疑问:我是以iPhone6的尺寸为基础进行设计和标注的,怎么可能在一个正方形上根据我标注的尺寸定好它们的位置关系,放到这个正方形上,个人标注不是全乱了吗?答案是,是,也是否是。若是你在设计和标注时只为iPhone6设计,把适配的问题都抛给了工程师,颇有可能最后出来的结果不是你想要的。相反,即便你是在iPhone6上进行设计,可是你并无把思惟局限在某个尺寸上,那么你的标注放在正方形上也不会乱。code
确切的讲,若是你是以约束为基础(constraint-based)来设计的界面,那么不管屏幕怎么变化,你的设计也会跟着进行调整。htm
下面我就来说讲AutoLayout究竟是如何工做的,以及该如何用约束的思想来进行设计。blog
对于iOS开发来说,一般会使用的是两种布局方式。一种是使用代码设置每一个视图(View)的Frame来进行定位。另外一个则是使用AutoLayout进行布局(能够在storyboard上,也可使用代码)。假设咱们在iPhone6(375*667)的尺寸下放了有两个视图,A和B。图片
Tips:在iOS开发中使用的单位是point,也就是@1x下的尺寸。若是你是以iPhone6(750*1334Px)的尺寸进行设计的,那么里面的尺寸都要除以2才能用。因此建议你们在@1x的环境下设计。本文不作特殊说明,没标单位的标注,默认单位都为point。
1.Frame定位
设置Frame进行定位的方法不是本文讨论的重点,我只在这里简单介绍一下。首先在iOS里的坐标系和咱们平时用的有点不一样。它的坐标原点在左上角。每一个视图都有本身独立的坐标系。见下图。
图3,使用FRAME进行定位
一般咱们定义一个Frame的代码(Swift)是这样的:
1
|
let frame = CGRectMake(x:CGFloat, y:CGFloat, width:CGFloat, height:CGFloat)
|
固然你不须要看懂它,只须要知道它要你提供四个参数:x,y,width,height。x ,y 是你要定位的视图的原点相对于包含它的视图的(superView)坐标系的坐标。width,height 固然就是你要定位的视图的宽度和高度了。
总结一下就是你须要提供位置信息(location)以及尺寸(size)信息。
因此上图中A,和 B的Frame应该是这样的:
1
2
|
let frameA = CGRectMake(60, 60, 255, 160)
let frameB = CGRectMake(60, 280, 255, 160)
|
2.AutoLayout定位
AutoLayout布局背后的逻辑则彻底不一样于上一种方式。同一个图,AutoLayout能够用下图这种方式来表示。
图4,AUTOLAYOUT布局
AutoLayout是一般是经过定义一系列的约束(constrains)来进行定位的。和Frame定位同样,它一样须要你提供位置和尺寸信息,可是和Frame不一样的是,它不是让你直接提供x,y,width,height,而是经过你给的约束来推断出相应的尺寸和位置。只有当能从你给的约束关系中推断出位置和大小信息,并且尚未冲突时,才能经过。
如上图中的视图A,咱们经过上下左右四个约束定好了它的位置。咱们提供了它的高度,可是咱们并无给出它的宽度。以前说过,要肯定一个视图的布局,你须要提供位置以及尺寸信息。而这里咱们却没有提供宽度。应为宽度不是一个固定的数值,须要AutoLayout本身经过现有的约束来推断出视图A的宽度 = 375(屏幕宽度)— 60—60 = 255,这样当屏幕宽度变化时,视图A的宽度也会随之变化。
AutoLayout可以根据你在相应视图上设置的约束,自动计算出的你定义的视图的位置和大小。
图5,当外部环境(屏幕宽度)变化时
当周边环境变化时,它也随之改变,这就是AutoLayout能适配不一样屏幕的秘诀。
AutoLayout的应用并不局限于应对外部环境的变化(屏幕大小变化),即便在同一个屏幕内,当页面内容开始变化时,AutoLayout也能作出相应的调整。假设如今由于某种缘由,视图A的高度变为了210。那么就会出现如下两种结果:
图6左,FRAME
图6右,AUTOLAYOUT
用Frame定位方式,由于视图A,B的位置信息是独立的,A的变化,并不会影响B的位置,因此当A变高时,A,B之间高度方向的距离就被压缩了,能够想象,当A继续变高时,A和B之间就会出现叠加的状况,这显然不是咱们但愿看到的效果。
而AutoLayout则不一样,因为B高度方向的位置是相对于A的,因此当A变高时,B的位置也会跟着变化。这固然是咱们但愿看到的结果。
因而可知,AutoLayout的应用场景不局限于适配不一样的屏幕尺寸,即便在软件运行的过程当中,当页面变化时它也可以跟着调整。
须要提一下的是,使用Frame定位的方式也是能实现上面这种AutoLayout的效果的,反之咱们也能使用AutoLayout来实现像Frame这种A,B不相互影响效果,我在这里不细说,有兴趣的能够本身去思考一下。举这个例子,只是为了说明绝对定位和相对定位的区别。
3.AutoLayout 的属性(AutoLayout Attributes)
相对于Frame一般要你提供的x,y,width,height,AutoLayout可用的属性则多的多,经常使用的属性有这些:
Left
Right
Top
Bottom
Leading
Trailing
Width
Height
CenterX
CenterY
Baseline
查看全部属性可点击这里:NSLayoutConstraint
图7,AUTOLAYOUT 属性
这些属性也大概能够分为两类:大小(size)如width ,height ;位置(Location)如Leading,Trailing,Top,Button。
有了这些属性,咱们不只可以定义不一样视图之间的距离,让它们对齐,定义不一样视图之间的相对尺寸,甚至能够定义一个视图的长宽比。
值得注意的是其中的Leading 和Trailing,并不等于Left和Right。Leading表明的是阅读开始位置。一般咱们都是习惯从左边到右来阅读,这种状况下Leading就是Left,Trailing就是Right。但并非全部的国家都是依照这个方式的,好比中国古代的书,就是从右到左的,这时候Leading就在Right了。若是你的App用户是国际化的,须要注意这个问题。一般状况下,咱们都使用Leading,Trailiing。
图8,不一样语言环境下LEADING和TRAILING的区别
图9
假设咱们有以上两个View,如今要求他们间隔距离为8,如上图所示。那么他们之间的约束关系就能够这么表示:
1
|
ViewB.Leading = 1.0 x ViewA.Trailing + 8
|
其中1.0 是一个系数(Multiplier),这种状况下,这个系数为1.0
4.举个例子
下面就讲一个具体的例子来讲明一下AutoLayout应用。
假设我设计了一个这样的界面(375*667),接下来要交给工程师进行开发。个人要求以下:
1.三个视图离页面两边的距离都为37.5
2.每一个视图之间的距离,包括视图离页面顶端和底端的距离都要同样,为40
3.三个视图的宽度和高度要同样。
我按照这些要求进行了标注,如下就是我想达到的效果以及个人标注:
图10左,我要实现的效果
图10右,个人标注
先分析一下咱们的标注。
首先我要求每一个视图离页面两边的距离都为37.5。在标注里我很明确地说明了这个问题。
其次,我要求每一个视图之间的距离,包括视图离页面顶端和底端的距离都要同样,为40。在标注中我也很明确地说明了这一点。
最后,我要求每一个视图的宽度和高度要同样。在标注里,每一个视图的高度都标了169,符合我同样高度的要求。我给第一个视图标上了宽度300,其余两个和第一个首尾对齐,也是300,符合我同样宽度的要求。
乍一看这个标注没有问题。可是这里咱们确忽略了一个很重要的问题。这个图我是以iPhone6的尺寸来设计的,可是实际状况,它并不仅会出如今iPhone6的屏幕上。按照上面的标注,标注的总宽度 = 37.5*2 + 300 = iPhone6的屏幕宽度(375)。可是若是换一个手机屏幕,这个等式就不成立了。一样,高度也是这个问题。这样就和实际状况产生了冲突。
Tips:当你的标注在宽度方向,或高度方向的数值加起来等于某一个具体的屏幕尺寸时,你就须要去从新去检查你的标注了,须要说明那些尺寸是固定的,哪些尺寸是可变的。
显然,工程师没法知足你标注的全部尺寸要求。若是他只看到你给的标注文件,而不知道你的三点要求。那么这个标注在宽度方向大概就出现了如下几种可能性:
1.保持两边各37.5的边距(margin)要求,每一个视图的宽度根据屏幕的宽度来伸缩
2.每一个视图的宽度保持300不变,两边的边距根据屏幕的宽度来伸缩
3.视图的宽度和边距随着屏幕的宽度变化一块儿缩放
从咱们以前的要求来看,咱们但愿的是第一种可能性的,只是咱们的标注没有很好的说明这个点。工程师须要靠本身的理解来选择其中一种,有时候他的选择可能并非咱们想要的结果。
咱们该如何标注,来很好的表达个人要求?正确的标注应该是这样的:
图11,正确的标注方式
首先,我去掉了宽度的标注,就像上个例子说的同样,咱们须要AutoLayout本身来计算出它的宽度,也就意味着咱们是但愿每一个视图的宽度随着屏幕的宽度变化而变化。其次,我去掉高度的具体数值,只标了一个h。一样,由于屏幕的高度是不固定的,因此我没法给出具体的高度,可是我又要求每一个视图的高度是同样的。经过给每一个视图标注高度h,来表示他们的高度同样。
5.表达三种不一样可能性
以前我说过,我第一次给出的标注大概能够有三种不一样的理解,那么咱们又该如何来表达这三种可能性呢?下面我就来讲一下,如何使用AutoLayout的方式标注,来很明确地来表现以上三种可能性。
图12
第一个视图的标注,保持两边各37.5的边距(margin)要求,每一个视图的宽度根据屏幕的宽度来伸缩,这个上面说过。
第二个,我标注了宽度,没标边距。可是咱们要求它水平方向居中,经过这个约束来肯定它水平方向的位置。这样边距就能够根据屏幕的宽度变化而变化。
第三个,我标注了宽度为80%的屏幕宽度,这样它就能作到和屏幕一块儿缩放。
图13
我在Xcode上添加好了上面要求的约束,并选择在不一样的模拟器上运行。这样就能够看到咱们设计的页面在不一样设备上运行的效果了。如下就是它在不一样屏幕尺寸下显示的效果:
图14
能够看到,在iPhone6上如出一辙的三个视图,应为咱们设置了不一样的约束,在不一样的设备上运行就出现了不同的效果。由于AutoLayout是根据你设置的约束,自动计算出的你定义的视图的位置和大小。
为了适配更多的屏幕,咱们在设计的时候须要用相对定位的思惟来布局。