iPhone自诞生以来,随着其屏幕尺寸不断的多样化,屏幕适配的技术一直在发展更新。目前,iOS系统版本已经更新到9.3,XCode的最新版本已是7.3,仅iPhone历史产品的尺寸就已经有4种:3.5英寸、4.0英寸、4.7英寸、5.5英寸。最近,iPhone家族又诞生一款iPhoneSE,鉴于这款iPhoneSE的屏幕尺寸和iPhone5S的尺寸如出一辙——一样是4.0英寸,广大iOS开发者可算是松了口气,否则iOS的屏幕尺寸真的是愈来愈让人眼花缭乱。
按照时间顺序,屏幕适配是这样发展的:纯代码计算frame-> autoresizing(早期进行UI布局的技术,仅适用于约束父子控件之间的关系)->AutoLayout(iOS6/2012年、iPhone5被引入,比autoresizing更加高级,旨在替代autoresizing,能够设置任何控件之间的关系)->sizeClass(iOS8出现,用于解决愈来愈多的屏幕尺寸的适配问题)。
在iPhone3gs时代,手机的屏幕尺寸有且只有一种,也就是3.5英寸。开发app的时候,根本不用考虑同一个视图在不一样尺寸的屏幕上显示的问题。iOS开发者彻底能够用纯代码的方式把一个控件的frame写死。
后来apple公司推出了4.0英寸的iPhone5和iPhone5S,因此,针对于不一样尺寸的屏幕,再把控件的frame写死就不可取了。(其实也不是不可取,不少iOS开发者作屏幕适配的时候不是用的autoresizing或autolayout,而是以代码的方式动态获取屏幕的尺寸,而后根据屏幕的尺寸来写死子控件的frame。使用这种方式你会在代码中无辜增长不少if...else... 的条件判断语句。另外一种方式是获取到屏幕的尺寸后,按照控件和屏幕的比例来设置控件的frame,其本质上也是写死frame。因此这两种方式都不可取,毕竟未来会回出现愈来愈多的屏幕尺寸。从开发的角度,重复繁琐的代码会牵绊住开发者的进度;从程序设计角度,这样的设计思路不够高级,且往后不易于拓展和维护。)程序员
iOS屏幕适配主要有三个技术,分别是Autoresizing、AutoLayout、SizeClass。利用纯代码计算视图的frame咱们在此就很少介绍。至于什么是Autoresizing?什么是AutoLayout?什么是SizeClass?咱们用SToryBoard的一张截图能够说明问题,以下图。编程
Autoresizing和Auto Layout不能共存,因此若是使用Autoresizing,就不能勾选Use Auto Layout。xcode
Autoresizing是早期iOS设备机型不多、APP界面布局相对简单的背景下产生的一种屏幕适配技术。早期的iOS设备机型不多、屏幕尺寸单1、APP界面相对简单,屏幕适配并无如今这么复杂,在当时这种背景下,产生了Autoresizing。当时这种状况下苹果推出Autoresizing也是能够理解的,可是若是放到如今这种大背景下,Autoresizing是不可以知足开发者的屏幕适配需求的,具体缘由请见下文。markdown
Xcode5以后,新建的项目默认使用AutoLayout。Autoresizing默认不启用,咱们能够去掉use Auto Layout前面的对勾来启用Autoresizing,以下图。app
有一种说法:autoresizing是为了解决iPad开发中横竖屏适配问题应运而生的。代码中的autoresizingMask和storyBoard中尺寸检查器中的Autoresizing是一回事。iPhone5开始,Xcode添加了autolayout功能。storyBoard默认采用autolayout,取代了以前的autoresizing。若是使用autoresizing,须要在如下位置去掉“Use Auto Layout”。框架
从上图看出,storyBoard中的的Autoresizing只能设置两个父子视图之间的相对位置关系,一共6条虚线,分别是周围的四条虚线和方块内部的两条线。周围的四条虚线分别表明子控件距离父控件上、下、左、右之间的距离关系/或者叫约束关系,周围的四条虚线所包围的小方块表明子视图,小方块内部的两条带双向箭头的线分别表明子控件的宽度和高度。
当咱们点击周围四条虚线时,虚线会变成实线,表明子控件和父控件在这个方向上的间距被固定了。当咱们点击子视图内部的虚线时,一样也变为实线,表明子视图的宽度或者高度被固定了。
举个例子:当咱们点击最左边的虚线时候,表明子视图距离父视图左边的间距被固定了,而其余三个方向的距离和宽高会随父视图的缩放二缩放。iphone
咱们不只能够在storyboard中使用Autoresizing来约束父子视图,也可使用代码来设置父子视图之间的位置关系。UIView有一个autoresizingMask属性,能够经过该属性来约束父子视图以前的位置关系,而且UIView还有一个BOOL类型的autoresizesSubviews属性,默认为YES,表明父控件会跟随子控件尺寸的变化而变化。和frame、bounds、center、transform等属性同样,autoresizingMask和autoresizesSubviews也是属于UIView的几何分类-UIViewGeometry中的属性。ide
@property(nonatomic) BOOL autoresizesSubviews; // default is YES. if set, subviews are adjusted according to their autoresizingMask if self.bounds changes @property(nonatomic) UIViewAutoresizing autoresizingMask; // simple resize. default is UIViewAutoresizingNone
查看注释,autoresizesSubviews属性的大意是:默认autoresizesSubviews = YES。若是UIView设置了autoresizesSubviews,那么他的子控件的bounds若是发生了变化,他的子控件将会根据子控件本身的autoresizingMask属性的值来进行调整。
那么autoresizingMask又是什么呢?
autoresizingMask是一个枚举值,做用是自动调整子控件与父控件中间的margin(间距)或者子控件的宽高。默认其枚举值是UIViewAutoresizingNone。以下是其所有的枚举值:工具
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 };
从上面给出的代码能够看出,autoresizingMask有7个枚举值,除了UIViewAutoresizingNone以外还有6个枚举值,分别对应storyboard中的那6条虚线。因此,storyboard和代码是相同的,不管什么视图,凡是能够经过storyboard进行设置的属性,都有与之对应的属性代码,咱们也可使用代码的方式实现。毕竟,storyboard中的属性最终仍是会翻译成可执行的代码,只不过XCode利用可视化的storyboard工具帮助咱们完成了代码完成的事情。
值得注意的是:autoresizingMask的枚举值是使用位移的形式给出的,这样设置的好处在于,当咱们使用代码给某个视图设置autoresizingMask属性时,咱们能够给autoresizingMask属性指定多个枚举值。指定方式以下:oop
[subView setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin |
 FlexibleLeftMargin];
甚至咱们可使用这种方式:
[subView setAutoresizingMask:5];
系统自动把5分解成5 = 4 + 1。而后咱们就能够知道:4 = 1 << 2 = UIViewAutoresizingFlexibleRightMargin;1 = 1 << 0 = UIViewAutoresizingFlexibleLeftMargin。因此上面的代码就被解释成:
[subView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin]; // 子视图距离父视图左右间距不变,宽度随父视图宽度的缩放而缩放。
不难发现,这样以位移的方式指定autoresizingMask枚举值,也契合了storyboard中能够给子控件设置多个方向的约束的情景。以下图:
注意:
Autoresizing只能设置父子视图之间的关系,也就是说,Autoresizing只能控制子视图和父视图之间的位置/大小关系。Autoresizing不能设置兄弟视图之间的关系,固然也不能设置彻底不相关的两个视图之间的关系。正由于Autoresizing只能设置父子视图之间的关系,因此,Autoresizing只能应用于两个视图之间,不能应用于三个或者更多视图之间。毕竟,一个儿子不可能有两个亲爹。注意:
UIView的autoresizesSubviews属性为YES时(默认为YES),autoresizingMask才会生效。也就是说,当咱们想要利用autoresizingMask指定某个控件和其父控件的关系时候,必须autoresizesSubviews = YES。注意:
值得注意的是,autoresizingMask的每一个枚举值都带有Flexible
这个单词,其意思是:灵活的,弹性的。因此,咱们在对其枚举值进行一一翻译。
UIViewAutoresizingNone // 就是不自动调整。 UIViewAutoresizingFlexibleLeftMargin // 自动弹性的调整与superView左边的距离,保证与superView右边的距离不变。 UIViewAutoresizingFlexibleRightMargin // 自动弹性的调整与superView的右边距离,保证与superView左边的距离不变。 UIViewAutoresizingFlexibleTopMargin // 自动弹性d调整与superView顶部的距离,保证与superView底部的距离不变。 UIViewAutoresizingFlexibleBottomMargin // 自动弹性的调整与superView底部的距离,也就是说,与superView顶部的距离不变。 UIViewAutoresizingFlexibleWidth // 自动弹性的调整本身的宽度,保证与superView左边和右边的距离不变。 UIViewAutoresizingFlexibleHeight // 自动弹性的调整本身的高度,保证与superView顶部和底部的距离不变。
看完翻译才恍然大悟,原来这些枚举值和storyboard中的虚线是相反的,当咱们点击了storyboard中国的某个虚线后表明其间距被固定,而咱们用代码设置则表明相反方向的间距被固定。
可是,例外的是,storyBoard中子控件内部的两个带箭头的虚线和枚举值UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
具备相同的意义。也就是说,当咱们点击了storyBoard中子控件内带箭头的水平虚线使之变为实线时,就至关于[subView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
当咱们点击了storyBoard中子控件内带箭头的垂直虚线使之变为实线时,就至关于[subView setAutoresizingMask UIViewAutoresizingFlexibleHeight];
注意:
简而言之,4条margin虚线表明设置autoresizingMask中的与之对应的4枚举值,而实线的width和height才表明设置autoreMask中与之对应的2个枚举值。
autoresizingMask枚举值及其对应的storyBoard预览效果说明
UIViewAutoresizingMaskNone
view的frame不会随superview的改变而改变,至关于frame(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin
view和其superView左间距和上间距固定,宽高固定,右间距和底部间距随父控件的缩放而按比例缩放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView上间距固定,右间距固定,宽高固定,左间距、下间距锁父控件的缩放而缩放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin
view与其superView的右间距、底部间距固定,宽高固定,上间距、左间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin
view与其superView的左间距、底部间距固定,宽高固定,右间距、上间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight
view与其superView的上间距、左间距、底部间距固定,宽度固定。高度、右边距随父控件缩放而缩放
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左间距、上间距、右间距固定,高度固定。宽度、底部间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight
view与其superView的上间距、右间距、底部间距固定,宽度固定。高度、左间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左间距、右间距、底部间距固定,高度固定。宽度、上间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、上间距、底部间距固定。宽度、高度、右间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、上间距、右间距固定。宽度、高度、底部间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的上间距、右间距、左间距固定。宽度、高度、左间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view与其superView的左间距、底部间距、右间距固定。宽度、高度、上间距随父控件的缩放而缩放
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottom
view与其superView的宽高比例维持不变,上下左右间距也随其superView的缩放而缩放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin
view与其superView的左右间距固定,高度固定,宽度、上间距、底部间距随其父控件的缩放而缩放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView的上下左右边距的比例维持不变,宽高固定,反映在storyBoard中,就是什么都不设置
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin
左边距、右边距、宽按比例调整,上边距固定,下边距固定,高度固定(右图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)垂直方向是一样效果,故不列举
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
自动调整view的宽和高,保证上下左右边距不变。如把tableView设置为此属性,那么不管viewController的view是多大,都能自动铺满
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin
view与其superView的左边距和右边距的比例维持不变,上下间距固定,宽高固定(下图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)这种约束方式至关于上下间距固定,宽高固定,那么父控件高度缩放的时候就会产生冲突,因此这种布局方式是不合理的
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view与其superView的上边距和下边距的比例维持不变,左右间距固定,宽高固定(这种约束方式至关于左右间距固定,宽高固定,那么父控件宽度缩放的时候就会产生冲突,因此这种布局方式也是不合理的)
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth
view与其superView的左边距和width按比例调整,高度固定,右边距固定,上边距固定,下边距固定(下图的xib中预览效果与实际效果有差,实际效果是view的上边距不变)(这种约束方式至关于上下间距固定,高度固定,那么父控件高度缩放的时候就会产生冲突,因此这种布局方式也是不合理的)
综上发现,只要是咱们在水平方向同时固定了左边距和右边距,那么咱们千万不能固定子控件的宽度(反应在storyBoard中的设置,也就是必须使控制子控件宽度的虚线变为实线)。同理, 若是垂直方向同时固定了上边距和下边距,那么咱们不能固定子控件的高度(反应在storyBoard中的设置,也就是必须使控制子控件高度的虚线变为实线)。
注意:
若是咱们在storyBoard中选中控制器的view,而后在尺寸检查器中查看会发现,autoresizing中控制子控件的宽度和高度的虚线自动变成了实线(然而我并无点击),这是由于控制器的view的宽高是一个默认值,默认和屏幕的尺寸相等,因此咱们不能经过autoresizing来设置控制器的宽高。从另外一个角度也能解释:autoresizing是约束子控件和父控件之间的位置关系的,控制器的view并无父控件,因此不能经过autoresizing来约束控制器的view。
AutoLayout的前身是Autoresizing,也就是说,AutoLayout旨在替代Autoresizing。AutoLayout自iOS6开始引入,但因为当时XCode4当时对AutoLayout的支持不是很好,因此在XCode5/iOS7及其以后,AutoLayout才开始被普遍应用。注意:
既然前面已经说了,AutoLayout旨在替代Autoresizing,因此在同一个项目中,AutoLayout和Autoresizing是不能共存的,两者只能选其一,若是你选择了AutoLayout,那么Autoresizing自动被屏蔽掉;若是你选择了Autoresizing,那么AutoLayout自动被屏蔽掉。XCode5及其以后的版本,默认新建的项目就是使用AutoLayout,不过咱们能够在项目中进行更改,以下图。
Auto Layout is a Constraint-Based, Descriptive Layout System.
翻译过来大意是:autolayout是一个基于约束的、描述性的布局系统。autolayout之因此可以进行屏幕适配,是由于他和autoresizing同样,都是对屏幕上的控件相对位置的设置,而不是绝对位置。用苹果官方的话,Auto Layout是一个基于约束的,描述性的布局系统。所谓基于约束就是表明咱们能够为须要布局的子控件添加一些约束对象来限制他在屏幕上显示的位置。所谓描述性是指其约束的设置可读性较高,接近于人类语言。
1.约束 每在Storyboard中对控件添加一个约束(autolayout的约束), 就表明添加一个约束对象。好比,给storyBoard中的某个子控件A设置了宽度和高度、距离父控件上下左右之间的间距,就至关于给这个控件添加了6个约束,也就产生了6个约束对象。 2.约束错误(红色箭头) 若是看到Storyboard中有红色的箭头, 表明约束有错误 注意: 约束有错误, 不表明运行会错误, 约束有错误一样能够运行 注意: 红色箭头是程序员必须解决的 3.为何会有约束错误? 3.1缺乏约束 3.2约束冲突 3.1缺乏约束 >autolayout的本质和frame差很少 >若是经过frame来设置一个控件, 必须设置这个控件的x/y/width/height, 控件才能按照咱们的需求显示 >若是是经过autolayout来设置一个控件, 也必须设置这个控件的x/y/width/height, 控件才能按照咱们的需求显示 >也就是说, 若是说x/y/wedth/height只要有一个没有设置都会报错, 就是缺乏约束 >由于autolayout对控件的约束是一种相对位置的约束,因此咱们能够经过间接的方式来设置约束。好比,给某个子控件A设置了左边距和右边距后,虽然没有明确指定子控件A的宽度,可是其左右边距一旦设置,那么宽度能够根据子控件A和父控件左右之间的边距自动推算出来。这就是我所说的间接的、相对位置的约束。 3.2约束冲突 >约束能够重复添加,但容易引起约束冲突 >例如先约束某个子控件A的高度等于100,而后又给这个子控件A添加了一个高度约束, 约束高度等200, 那么这两个约束就产生了冲突,控件A不知道他本身的高度是100仍是200,因此就会产生约束冲突,系统就会报错。 红色: 距离顶部有20 == 至关于设置了Y 距离左边有20 == 至关于设置了x 设置宽度等于100 设置高度等于100 4.约束警告 若是看到Storyboard中有黄色的箭头, 就是警告 > 警告表明着当前控件在storyBoard中呈现的位置或者尺寸和程序运行后实际呈现的效果不同,致使约束警告的缘由每每是没有更新控件的约束,但并不影响其真实效果,也不会报错。 */
}
注意:
用storyBoard设置约束的时候,注意有一个Constrain to margins,默认打勾,也就是默认会给视图添加一个20的左右边距(上下不会添加),目的是让视图在iPhone6P和iPhone6SP上显示的更好看一些。
1.两个同层级view之间的约束关系,添加到他们共同的父view上
2.两个不一样层级上的view之间的约束关系,添加到他们最近的共同的父view上
3.两个有层次关系的view之间的约束关系,添加到层次较高的view上
4.若是view的约束只和本身有关系,那么添加到本身身上。好比宽高约束。
UILabel默认内容的显示方式是垂直居中的。若是用autolayout给UILabel设置约束,只须要设置x、y、width,无需设置height,UILabel会自动包裹内容,而且随内容的多小而变化。若是咱们经过约束给定了UILabel的width = 100,可是内容仍然少的可怜,不能包裹,能够把宽度设置为<=100,此时,label的宽高都能包裹住内容。高度的设置同理可证。
固然,咱们也能够只给UILabel设置x、y。但必需要保证UILabel的text属性有内容,不然UILabel显示不出来(这是初学者常常犯的错误)。缘由在于,UILabel是根据内容自动调整宽度和高度,若是没有内容,那么宽度和高度就是0,致使UILabel没法显示。
若是但愿父控件随子控件(UILabel/UIView)高度的变化而变化,就不要给父控件添加高度约束,只须要子控和向父控件在垂直方向上添加约束,这样子控件高度改变,父控件高度也会随之改变。
事实上,咱们在xib或者StoryBoard上给控件添加的约束,也是会被翻译成代码执行的。那么添加的那些约束会被翻译成什么呢?本质上,在xib或者StoryBoard上添加的也U树都是NSLayoutConstraint类型的对象。能够经过在StoryBoard上的控件和对应的.h或者.m文件之间拖线添加IBOutlet引用来证实。
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *topConstraint; @property (weak, nonatomic) IBOutlet UIView *customView; @end @implementation ViewController - (void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // WSLog(@"%f", self.heightConstraint.constant); self.heightConstraint.constant += 10; self.topConstraint.constant += 100; [UIView animateWithDuration:2.0 animations:^{ [self.customView layoutIfNeeded]; }]; } @end
以下图,假设给控制器的view添加一个宽高均为100、水平、垂直居中的控件
代码以下:
// 1.建立控件 UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; #warning 注意: 经过代码给子控件添加Autolayout约束,必需要先把子控件添加到父控件身上! // 2.建立约束 #warning 注意点: 若是经过代码来设置Autolayout约束, 那么必须先禁用Autoresizing redView.translatesAutoresizingMaskIntoConstraints = NO; // 2.1宽度 NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0 constant:100.0]; // 将约束添加给本身 [redView addConstraint:width]; // 2.2高度 NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0 constant:100.0]; // 将约束添加给本身 [redView addConstraint:height]; // 2.3水平居中 NSLayoutConstraint *xCos = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]; // 将约束添加到层次较高的父view上 [self.view addConstraint:xCos]; // 2.4垂直居中 NSLayoutConstraint *yCos = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]; // 将约束添加到层次较高的父view上 [self.view addConstraint:yCos];
Masonry是目前最流行的、最经常使用的AutoLayout的第三方开源框架。Masonry采用链式编程思想,极大的方便了开发者。你们能够在GitHub上找到Masonry。
一样的问题,仍是给控制器的view添加一个宽高均为100、水平、垂直居中的控件的Masonry的代码,看起来就简洁多了,Masonry代码以下:
// 1.建立一个控件 UIView *redVeiw = [[UIView alloc] init]; redVeiw.backgroundColor = [UIColor redColor]; [self.view addSubview:redVeiw]; // 2.禁止红色View的Autgoresizing redVeiw.translatesAutoresizingMaskIntoConstraints = NO; [redVeiw mas_makeConstraints:^(MASConstraintMaker *make) { make.width.equalTo(100); make.height.equalTo(100); make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); }];
注意:
通常状况下,多数使用storyBoard中的autolayout设置约束,只有在万不得已的状况下才用代码设置autolayout约束,这种状况通常是,被约束的控件是代码建立的,或者被约束的控件的父控件是代码建立的。
本篇文章没有讲解苹果自家的AutoLayout语言—VFL。由于笔者对VFL不使用很少,工做中几乎没有用到过,因此本篇文章就略过,感兴趣的读者能够本身研究。
以下图,就是sizeClass:
iOS8/XCode6才开始引入的。SizeClass依赖于AutoLayout,也就是说,若是你的项目中用到了SizeClass,那么必需要使用AutoLayout。因此,不存在SizeClass和Autoresizing联合使用的状况!
确切的说,sizeClass并非一种屏幕布局技术,经过上面对autoresizing和autolayout的介绍,咱们知道了autoresizing和autolayout是对屏幕上控件的相对位置进行的设置,也就是说,autoresizing和autolayout是针对于屏幕上的子控件而产生的技术。但sizeclass是对不一样尺寸的屏幕的区分,sizeclass把不一样尺寸(包括横屏和竖屏)的屏幕进行了分类,不管是iPhone仍是iPad设备,其宽度和高度都被划分为三种类型:compact(紧凑)、regular(正常)、any(任意)咱们只要针对于某一类型的屏幕进行布局,那么布局出来的界面能够显示在属于该类型的全部尺寸的屏幕上。
不少人认为sizeclass对屏幕宽度和高度的区分分为三种,compact(紧凑)、regular(正常)、any(任意)。这三种类型进行组合能够有9种结果。但在我看来,sizeclass对屏幕的区分只有两种:compact和regular。any并非真正的类型,他只是表明了compact和regular。正像runLoop中的commonMode同样,并非一种真正的mode,只是表明了defaultMode和trackMode。
sizeClass尺寸对照:
通常状况下,StoryBoard中的sizeclass是(any,any)的。在sizeclass为(any,any)时布局的控件能够显示在任何尺寸的设备上,包括全部尺寸的iPhone和iPad。若是咱们选择sizeclass为(compact,regular),那么在storyBoard上布局的控件只会显示在宽度为“紧凑”,高度为“正常"状态的设备上,也就是全部的“竖屏状态”的iPhone上。横屏状态的iPhone不会显示这个控件,横屏和竖屏状态的iPad也不会显示这个子控件。
因此,当咱们但愿某个控件在横屏是显示,在竖屏时不显示的时候,能够考虑有sizeClass这种技术。
而且,在iPad开发时,针对于同一界面,咱们一般须要对横竖屏的iPad分别进行布局,此时也可使用sizeClass,咱们只须要切换storyBoard底部的sizeClass就能够布局初互不干扰的界面。
在出现sizeClass技术以前,咱们用xcode新建的universal项目默认会有两个storyBoard,一个是专门为iPhone开发的storyBoard,另外一个是专门为iPad开发的storyBoard。而在sizeClass出现以后,咱们新建的universal项目就只有一个main.storyBoard。由于经过sizeClass咱们能够在这一个main.storyBoard上为iPhone和iPad布局。
前面已经说过,咱们选中sizeClass中一种屏幕类型,进行的布局只会出如今响应的设备上。好比,我选中w Compact H Regular。也就是宽度紧凑,高度正常。那么在这种状态的storyBoard上布局的控件只会出如今竖屏的iPhone设备上,不会出如今横屏的iPhone设备上。不信你继续往下看:
1>选中storyBoard上的sizeClass为W Compact H Regular。下面会有提示:For all iPhone in portrait。也就是在这个状态下布局的控件只能出如今全部竖屏状态的iPhone上!
2>此时会发现storyBoard上的初始化控制器由原来的正方形(W Any H Any)变为iPhone状态的长方形。
3>给storyBoard上的控制器添加一个水平、垂直居中、宽高都为150的红色button。以下图:
4>而后咱们预览在4英寸的iPhone设备上,横屏和竖屏的显示状况,以下图:
从上图,你会发现,当我把iPhone切换到横屏状态时,本来在竖屏显示的红色按钮不见了。缘由就在于,这个红色按钮是在sizeClass为W Compact H Regular状态下添加给storyBoard上这个控制器的。这也验证了我前面说过的,sizeClass为宽度紧凑,高度正常状态时的布局智慧显示在全部竖屏的iPhone上。固然,此处,我只是拿4.0英寸iPhone举例,其余尺寸iPhone同理可证。在其余尺寸(3.五、4.七、5.5英寸)的横屏状态也不会显示。固然,在iPad全屏(横屏或竖屏)状态下一样不会显示。由于iPad 的屏幕尺寸根本就不在 W Compact H Regular这一列。
可是,在iPad分屏状态下是会显示的。
1>仍是上面的那个storyBoard,仍是上面的那个带有红色按钮的控制器。咱们如今把sizeClass切换为W Regular H Compact状态。以下图:
2>你会发现,在设置sizeClass为W Regular H Compact时,下面的提示是:For 5.5-inch iphones in landscape。也就是说,在W Compact H Regular状态下给控制器的View添加的子控件只会出如今5.5英寸的横屏状态下的iPhone上。同时你也会发现,在W Compact H Regular状态下给控制器的view添加的红色button不见了。以下图:
3>而后咱们给控制器的view左上角(此处的左上角是相对于垂直状态)添加一个绿色的button。以下图:
4>而后咱们预览在5.5英寸的iPhone设备上,横屏和竖屏的显示状况,以下图:
从上图,你会发现,咱们在W Regular H Compact状态下给控制器左上角添加的绿色的按钮只会显示在横屏状态下,切换到竖屏状态后,左上角什么都没有。这也验证了sizeClass为W Regular H Compact状态下的布局会出如今5.5英寸的横屏的iPhone上而不会出如今5.5英寸竖屏的iPhone上。
固然,切换到竖屏时,你一样发现了控制器中间出现了一个红色的按钮,没错,这就是咱们在上一个例子中(W Compact H Regular状态)设置的那个水平、垂直居中的红色button。这也再次验证了,咱们在不一样的sizeClass下的布局并不会相互影响。
咱们在W Regular H Compact状态下的布局不是说好了“只会”出如今5.5英寸的横屏状态下吗?上面只是验证了会出如今5.5英寸的横屏状态的iPhone上,可是并无验证“只会”这个词语。请看下图:
上图是以4.0英寸的iPhone设备为例进行的验证,你会发现,在4.0英寸的设备处于横屏状态时,左上角并无出现绿色的button。至此,咱们证实了sizeClass为W Regular H Compact时,在storyBoard上的控制器上的布局只会出如今5.5英寸的横屏状态的iPhone设备上。
1>仍是上面那个storyBoard,仍是上面那个控制器,咱们如今把sizeClass切换为W Regular H Regular,你会发现下面的提示:For iPads in portrait or landscape。也就是说,在sizeClass为W Regular H Regular状态下的布局只会出如今全部横屏或竖屏的iPad设备上,并不会出如今横屏或者竖屏的iPhone设备上。
2>和上面那个例子同样,咱们切换了sizeClass后,storyBoard上的控制器也变了形状--变成了和iPad同样方方正正的一个控制器。而且在左上角绿色的button不见了。"好像"变成了一个干干净净的控制器。
3>而后给控制器的右上角添加一个蓝色的button,以下图:
4> 而后咱们预览在iPad和iPhone设备上横竖屏的显示状况,以下图:
从上图,能够看出,在iPhone上不管是横屏仍是竖屏,右上角都没有显示那个蓝色的button。综上,验证了sizeClass为W Regular H Regular状态时,在控制器上的布局只会显示在iPad横屏或者竖屏状态下,而不会显示在iPhone的横屏或者竖屏状态下。
上面我列举了三种sizeClass状态下布局显示状况,而按照sizeClass的九宫格组合状况来看,sizeClass应该有9个不一样的组合。固然any表明了compact和regular(正常和紧凑)。好比,当咱们选择sizeClass为 W Regular H Any(宽度正常 高度任意)时,其实这表明了两个不一样的sizeClass:W Regular H Regular (宽度正常 高度正常)和 W Regular H Compact(宽度正常 高度紧凑)。也就是说,在sizeClass为 W Regular H Any(宽度正常 高度任意)状态下的布局至关于在sizeClass为 W Regular H Regular(宽度正常 高度正常) 和W Regular H Compact(宽度正常 高度紧凑)布局之和。换句话说,在sizeClass为W Regular H Any(宽度正常 高度任意)下的布局的控件,无论高度如何,只要宽度正常就会显示出来。
未完待续...
文/VV木公子(简书做者)
PS:如非特别说明,全部文章均为原创做品,著做权归做者全部,转载转载请联系做者得到受权,并注明出处,全部打赏均归本人全部!
若是您是iOS开发者,或者对本篇文章感兴趣,请关注本人,后续会更新更多相关文章!敬请期待!