iOS开发(一稿适配所有iOS设备)— AutoLayout入门

智能手机发展到今天,屏幕尺寸变的越来越多,iPhone从最初的3.5寸屏幕,到后来推出的4寸屏,直到苹果推出iPhone 6 和 iPhone 6Plus,也宣告着苹果阵营被彻底攻破,进入了屏幕尺寸碎片化的时代。只为某一个屏幕尺寸设计的日子已经不在存在。为了适配所有的屏幕,设计师必须考虑各种屏幕尺寸。但是又不可能为每个尺寸都设计一遍。那么我们又该如何面对屏幕碎片化的困境?

图1,图片来自:HTTP://WWW.PAINTCODEAPP.COM/NEWS/ULTIMATE-GUIDE-TO-IPHONE-RESOLUTIONS

苹果给出的答案是AutoLayout。让你能用一个设计来适配所有屏幕,理论上讲从iPhone4适配到iPad pro都可以。它希望你忘记某个具体的尺寸。实际上你可以随意拖出一个任意尺寸的画布进行设计,标注好后就可以交给工程师开发。

首先我们先看一下,苹果的开发软件Xcode上是让你怎么进行页面布局的。

图2,XCODE.STORYBOARD

中间那块白色的正方形就是画布,如果你是使用storyboard布局的话(iOS的布局方式有很多种,storyboard只是其中一种,我在后面会讲),你可以将你设计好的控件放到这个画布上去,根据你标注的尺寸定义好它们的位置关系,接下来AutoLayout就会自动适配各个屏幕了。听上去好像很神奇。

有些人会有疑问:我是以iPhone6的尺寸为基础进行设计和标注的,怎么可能在一个正方形上根据我标注的尺寸定好它们的位置关系,放到这个正方形上,我的标注不是全乱了吗?答案是,是,也是不是。如果你在设计和标注时只为iPhone6设计,把适配的问题都抛给了工程师,很有可能最后出来的结果不是你想要的。相反,即使你是在iPhone6上进行设计,但是你并没有把思维局限在某个尺寸上,那么你的标注放在正方形上也不会乱。

确切的讲,如果你是以约束为基础(constraint-based)来设计的界面,那么无论屏幕怎么变化,你的设计也会跟着进行调整。

下面我就来讲讲AutoLayout到底是如何工作的,以及该如何用约束的思想来进行设计。

对于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是根据你设置的约束,自动计算出的你定义的视图的位置和大小。

为了适配更多的屏幕,我们在设计的时候需要用相对定位的思维来布局。

时间: 2024-09-30 10:13:55

iOS开发(一稿适配所有iOS设备)— AutoLayout入门的相关文章

iOS开发:在多平台、设备及64位架构上运行

最近在新工程上线是遇到很多适配的问题,尤其是旧工程64位设备的适配,现在整理一下. Base SDK vs. Deplyment Target 1.配置Base SDK设置 1)选择工程导航面板上的工程文件 2)编辑面板上搜索base sdk Base SDK设置引导编译器使用该版本的SDK编译和构建应用,也就是说,它会直接控制应用使用哪些API. 2.Deplyment Target运行应用需要的最低操作系统版本 支持多个SDK时的注意事项: 框架的可用性有时新的SDK会增加一个完整框架,较早

iOS 开发之 - iOS6 适配, UITextField 文本,placeholder没有居中对齐

先上一张图: 为了方便观察,我给UITextField设置了一个背景颜色. 是不是赶脚偏了? 通过一个方法解决: _telTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; 如图: 就ok了.. iOS 开发之 - iOS6 适配, UITextField 文本,placeholder没有居中对齐

iOS 开发之 - iOS6适配 - 导航栏按钮透明方法

首先上张图: 1:ios6导航栏默认按钮 rightBarButtonItem   是不是很丑的赶脚? 现在通过以下方法来改变以下:code: UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeCustom]; rightButton.frame = CGRectMake(0, 0, 40, 40); [rightButton setTitle:@"提交" forState:UIControlStateNormal

从零开始学ios开发(六):IOS控件(3),Segmented Control、Switch

这次的学习还是基于上一个项目继续进行(你也可以新建一个项目)学习Segmented Control和Switch. Segmented Control Switch Segmented Control和Switch的主要区别在于Segmented Control可以有多个值进行选择,而Switch只有2个值. 1)添加Segmented Control从object library中拖一个Segmented Control到iphone界面上然后调整Segmented Control位置以及它的

从零开始学ios开发(五):IOS控件(2),Slider

下面继续学习ios的其他控件,这次会使用到的控件有Slider,当然还有一些之前已经使用过的控件Label. 这次我们不新建一个project了,当然如果你愿意重新创建一个新的项目也完全可以,我们还是使用上一篇的项目Control Fun. 上一篇中,我们最后的成果如下图所示我们添加了一个ImageView,2个Label和2个TextField,现在我们继续在此基础上添加其他的控件. 1)添加Slider和LabelSlider类似于一个滑块,左右(或者上下)滑动来改变数值,在object l

从零开始学ios开发(四):IOS控件(1),Image View、Text Field、Keyboard

长话短说,谢谢大家的关注,这篇写了好长时间,下面继续学习ios.我将用2到3篇的篇幅来学习iphone上的一些常用控件,包括Image View.Text Field.Keyboard.Slider等等,这篇的内容包括ImageView和Keyboard的使用.完成后的效果图如下: 1)创建一个新的project,选择“Single View Application”,命名为“Control Fun”,然后保存.一些和前几章相似的步骤在从这篇起就开始一笔待过了,也不再做截图了,例如这里的创建一个

iOS开发- 游戏屏幕适配(SpriteKit)

我们开发一个App的时候, 通常希望它在 iPhone, iPad, Mac上同时能运行, 尤其是游戏. 这样就需要我们考虑不同设备不同的分辨率,处理起来比较麻烦. 比如说,按照官方的做法,我们需要提供诸如 xx.png, [email protected], [email protected], xx~iPad.png, and [email protected] 这样不同的图片, 另外还有在程序中写大量 if (...){...} else if {...}这样的代码来区分不同的设备, 想想

ios开发——实用技术篇OC篇&获取设备唯一标识

获取设备唯一标识 WWDC 2013已经闭幕,IOS7 Beta随即发布,界面之难看无以言表...,简直就是山寨Android. 更让IOS程序猿悲催的是,设备唯一标识的MAC Address在IOS7中也失效了. IOS系统中,获取设备唯一标识的方法有很多: 一.UDID(Unique Device Identifier) UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成. 二.UUID(Univers

李洪强iOS开发之零基础学习iOS开发】【02-C语言】01-概述

前面已经给大家介绍了iOS开发相关的一些基础知识,其实iOS开发就是开发iPhone\iPad上的软件,而要想开发一款软件,首先要学习程序设计语言.iOS开发需要学习的主要程序设计语言有:C语言.C++.Objective-C,其中C++.Objective-C都是以C语言为基础,从C语言衍生出来的.从这讲开始,我们就暂时抛开iOS相关的知识,沉下心来学习传说中的C语言.正式学习之前,先提醒一句:学习一门语言的语法是比较枯燥的事,很像是在学习1+1等于几,不可能说,学习C语言语法过程中就能马上做