如今苹果生态圈中的设备尺寸也已经变得种类繁多了,设备种类以下:
iPad:iPad1,iPad2,newPad,iPad4,iPad air,iPad air2,iPad mini1,iPad mini2,iPad mini3,iPad pro;
iPhone:iPhone3Gs,iPhone4,iPhone4S,iPhone5,iPhone5S,iPhone5C iPhone6,iPhone6 Plus,iPhone6S,ipad iPhone6S Plus;
iWatchios
屏幕大小:markdown
想必苹果也意识到这一点。都知道苹果是以化繁为简的设计哲学深刻人心的,此次再一次证实了。SizeClass是对设备尺寸的一个抽象概念,如今任何设备的 长、宽 被简洁地分为三种状况:普通 (Regular) 、紧密 (Compact) 和 任意(Any) ,这样,根据长和宽不一样的搭配就能产生 3 * 3 = 9 种不一样尺寸。下图展现个每种状况对应的设备。工具
之前为不一样的iOS设备尺寸或者同尺寸横竖屏不一样适配UI,都要根据实际状况而去计算frame。使用Size Classes是根据当前的屏幕size类型而使用Auto Layout方式进行布局了,要摒弃以前计算frame的思路,而改用相对布局的思惟去思考(实际上仍是要计算frame).布局
并且Xcode6最大的突破也是这里,不在须要创建不一样尺寸的storyboard了,只要创建一个,而后修改其view的size就能够作各类屏幕尺寸的适配,以下:动画
例如我要作iPad页面设计,就设置成w (Regular)/h(Regular)ui
而后一样的工程,又要兼容横屏的iPhone6 plus,就能够把view的size class设置成:w (Regular)/h(Compact),而后继续适配spa
而后当程序跑在不一样的设备上,或者设备横屏和竖屏切换,就能显示相应的UI了。.net
示例:设计
适配iPhone6,在RootViewController的view上添加一个新的view,让这个新的view不管屏幕横屏仍是竖屏时候都距离其superview的边缘50点宽,而且横屏时候为绿颜色,竖屏时候为红颜色。3d
操做以下:
而且添加一个view,不用管其frame,并设置其背景色为红色
接下来选中红色的view,而后点击Xcode顶部工具栏的Editor-Pin,而后分别添加红色view相对superview边框的约束(上下左右
添加约束的过程当中会看到约束的线是黄颜色,代表当前的约束还不能肯定view的frame,须要继续添加,当添加完4个约束后,约束线的颜色是蓝色的,代表当前约束是正确的。
而后选中约束,设定约束的值(咱们不是想让新的view距离其superview边界50点宽吗!),4个约束都要设置。
设置完后点击下view会自动更新frame,应该是这样的:
2.切换size class为wRegular/hCompact模式,而后重复第一步中的设置,区别是新添加的view背景颜色设置为绿色。
示例2:
基于iPhone适配界面,添加三个view到rootView上,而后不管横屏仍是竖屏,新添加的三个view之间及与屏幕边框的距离都保持不变的间距20点宽,效果如图:
由于要适配iPhone横竖屏,因此修改size class为wCompact/hRegular来适配竖屏:拖拽3个view到rootView上,并设置其背景颜色
为了知足设计要求,要添加以下constraint:
操做以下:
选中绿色view,Eidtor->Pin->Leading Space to Superview给绿色view添加相对其superview的左边距,而后选中constraint,修改约束的值为20,其余constraint以此类推
添加完如图:
其中红色框部分清晰的表达了所添加的constraint;蓝色框部分时添加的constraint,目前为黄色线,代表当前的constraint还不能定位view,当一个view的constraint正确的时候,constraint的颜色会变为蓝色。绿色线框的部分表达了constraint的数值,咱们想让边距为20,因此设置数值为20 。wC hR Installed代表当前constraint适用于wC hR这种size class,不适合any any的size class。
添加绿色view与黄色view以前的距离时候,因为是设定两个子view的constraint,因此要选中两个view,而后Editor->Pin ->Horizontal,设定值为20:
一样方法Editor->Pin ->Width Equally,设定绿色view与黄色view等宽度,蓝色view与绿色view等高,结果如图:
但发现constraint颜色仍而后黄色,缘由是当前view的位置和constraint但愿的不一致,更新下frame(要选中3个view,由于constraint关联3个view)或者点击Document Outline中的黄色小箭头,而后会看到具体的constraint信息来一步步调试,这个也是Xcode6最有突破的地方:
而后效果如图:
而后运行下项目吧,发现确实和预期的同样。而后旋转屏幕,是否是发现横屏时候白了,屏幕什么都没有了?缘由是咱们仅仅适配的竖屏,横屏尚未适配啊!
修改size class,iPhone4s横屏的size class为wCompact/hCompact,而iPhone6 plus为wReguage/hCompact,那咱们不如设置为wAny/hCompact吧!而后安装上边适配竖屏的方式适配横屏。适配好后再次运行,横竖屏都应该是咱们想要的了。
小小技巧: 查看不一样设备适配状况
在 ios6 以前没有AutoLayout布局UI,咱们布局UI是基于固定的frame,bound对控件的布局,设置控件的 位置(x,y), 尺寸(width,height)就能够把控件放在相应的位置。
出现Autolayout后,咱们用AutoLayout布局控件就要把以前固定设置frame、bound忘记;要想布局显示一个控件,Autolayout以两个词:约束,参照 动态设置一个控件两个东西,位置,尺寸;
小结:
1. 添加约束不宜过多,当添加的约束足以表达该控件的位置与尺寸,就足够了 2. 约束就是对控件的大小或者位置进行约束,参照就是以某个控件的位置进行约束,其实这二者没有明确的分别,它们均可以对控件的位置与尺寸起到做用。
1)手动添加约束(苹果官方API)
/** * 这个是系统默认添加约束的方法,它是NSLayoutConstraint的类方法 * * @param view1 传入想要添加约束的控件 * @param attr1 传入想要添加约束的方向,这个枚举值有不少,能够本身看看 * @param relation 传入与约束值的关系,大于,等于仍是小于 * @param view2 传入被参照对象 * @param attr2 传入被参照对象所被参照的方向,如顶部,左边,右边等等 * @param multiplier 传入想要的间距倍数关系 * @param c 传入最终的差值 * * @return NSLayoutConstraint对象 */ +(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c //一部分NSLayoutAttribute枚举值 NSLayoutAttributeLeft = 1,//控件左边 NSLayoutAttributeRight,//控件右边 NSLayoutAttributeTop, NSLayoutAttributeBottom, NSLayoutAttributeLeading,//控件左边 NSLayoutAttributeTrailing,//控件右边 NSLayoutAttributeWidth,//控件的宽 NSLayoutAttributeHeight,//控件的高 NSLayoutAttributeCenterX,//竖直方向中点 NSLayoutAttributeCenterY,//水平方向中点
这个方法的参数我很想用形象的语言描述出来,可是仍是想不出,更多须要你们从下面的代码中传入的参数去体会
//建立redView UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; redView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:redView]; //建立redView第一个约束,相对self.view的左边缘间距20 NSLayoutConstraint * redLeftLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeLeftMargin relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:20.0]; //只有在没有参照控件的状况下,约束才加到自身,否则加到父控件上 [self.view addConstraint:redLeftLc]; //建立redView第二个约束,相对self。view的底边缘间距20 NSLayoutConstraint *redBottomLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottomMargin multiplier:1.0f constant:-20];//因为是redview相对self.view往上减20,因此是-20 //添加约束 [self.view addConstraint:redBottomLc]; //这里直接设置自身宽为50 NSLayoutConstraint * redWLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; //因为没有参照物,因此约束添加于自身身上 [redView addConstraint:redWLc]; //建立最后一个约束,自身的高 NSLayoutConstraint * redHLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50]; //因为没有参照物,因此约束添加于自身身上 [redView addConstraint:redHLc];
运行的效果图
接下来咱们继续增长需求,在红色方块的右边放一个离它20间距,离self.view底部也间距20,宽高相等的蓝色方块
//先建立一个一个蓝色的view添加到视图上,剩下的就是用autolayout来设置它的“frame”了 UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; blueView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:blueView]; self.blueView = blueView; //建立第一个约束,左边间距,因为是想要与红色有20的间距,那么参照参数“toItem”就应该填redView NSLayoutConstraint *blueLeft = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20.0f]; //与其余控件发生约束,因此约束添加到父控件上 [self.view addConstraint:blueLeft]; //如今咱们已经能够肯定本身水平方向的位置了,还差垂直方向的位置,如今咱们来建立第二个约束,参照物依然是红色方块,需求是要离self.view底部20间距,这不是正好和红色同样么,那么咱们能够直接与红色方块底部对齐就好了 NSLayoutConstraint *blueBottom = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];//与红色方块底部对齐,倍数1.0f.差值0.0f //与其余控件发生约束,因此约束添加到父控件上 [self.view addConstraint:blueBottom]; //剩下两个约束差很少,我就一并描述了,它们都以redView为参照,与其等宽等高 NSLayoutConstraint *blueW = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; [self.view addConstraint:blueW]; NSLayoutConstraint *blueH = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; [self.view addConstraint:blueH];
接下来看看效果图
小结:
1.其实Autolayout的思想很是简单,刚开始使用的时候不要想着立刻一鼓作气,最好一个控件一个控件的实现依赖,分别知足其位置与尺寸的需求,若是一会儿几个控件一块儿弄的话,每每你们犯错是犯在约束添多了,而不是添少了。 2.就如上面的例子,不少人会在设置了与红色等高等宽后,还同时去添加顶部对齐与底部对齐,这样高度就重复设置了,他会忽略了,上下同时对齐不只给予了垂直位置,也给予了高度,因此思路必须清晰!
Autolayout 下添加动画
我将在蓝色方块的右边再加个一样大小的黄色方块,而后,要求点击屏幕,而后蓝色方块被移除,黄色方块替代蓝色方块的位置
还有一个autolayout的知识点:优先级(priority)
//一如往常,先建立黄色View UIView *yellowV = [[UIView alloc]init]; yellowV.backgroundColor = [UIColor yellowColor]; yellowV.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:yellowV]; //开始建立约束,第一个约束是什么呢?一看就知道是左间距约束啦 NSLayoutConstraint *yellowLeft = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20]; //与其余控件发生约束,因此约束添加到父控件上 [self.view addConstraint:yellowLeft]; //添加底部约束 NSLayoutConstraint *yellowBottom = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-20]; //与其余控件发生约束,因此约束添加到父控件上 [self.view addConstraint:yellowBottom]; //这里我直接设置宽高约束了,就省事不加参照控件了 NSLayoutConstraint *yellowW = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; [yellowV addConstraint:yellowW]; NSLayoutConstraint *yellowH = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0f constant:50.0f]; [yellowV addConstraint:yellowH];
运行效果
接下来我再给黄色View添加一个约束,这个约束涉及到优先级,你们注意看代码了哈
//对黄色View添加约束,约束黄色view与红色View的间距为20 NSLayoutConstraint *yellowAnotherLeft = [NSLayoutConstraint constraintWithItem:yellowV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeRight multiplier:1.0f constant:20]; UILayoutPriority priority = 250;//设置优先级 yellowAnotherLeft.priority = priority; //与其余控件发生约束,因此约束添加到父控件上 [self.view addConstraint:yellowAnotherLeft];
想必你们应该看出些端倪了,我在前面已经给黄色View添加了对蓝色View间距位20的view,如今又给黄色view对红色View添加一个间距20的约束,这很明显是不可能出现的状况,黄色View怎么可能同时作到这两个约束呢,用术语来讲就是约束冲突,可是你们注意看这段代码
UILayoutPriority priority = 250;//设置优先级
我给yellowAnotherLeft这个约束添加了优先级,优先级的范围是0~1000,数字越大,优先级越高,在不设置的状况下默认为1000
这说明了,我最后添加的这个约束的优先级是低的,这个约束只有在它的冲突约束被抹掉后,它才能实现
也就是说,我把蓝色view移除后,黄色View相对于蓝色View左间距20这个约束就不成立了,那么黄色view会自动的变为与红色View间距20
让咱们最后加几行代码,来实现这个动画吧!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //先把蓝色方块从父视图上移除 [self.blueView removeFromSuperview]; //动画更新界面 [UIView animateWithDuration:1.0f animations:^{ [self.view layoutIfNeeded]; }]; }
autolayout的动画就是这样实现的,将操做代码走完后,再让动画块去更新界面,动画就出来了,效果以下:
2)VFL(visual format language)
需求:适配iPhone6,在RootViewController的view上添加一个新的view,让这个新的view不管屏幕横屏仍是竖屏时候都距离其superview的边缘20
H:|-20-[newView]-20-|
V:|-20-[newView]-20-|
每个 [] 中表示一个视图或一个控件;V 表示垂直约束,H 表示水平约束,而后两个视图之间的 -0- 的意思就很简单了,意思就是这两个视图之间间隔为0
好比:
V:[view0(67)]-0-[view1(67)]-0-[view2(67)]-0-[view3(67)]-0-[view4(67)]-0-|
self.view.translatesAutoresizingMaskIntoConstraints = NO; UIView *newView = [UIView new]; newView.backgroundColor = [UIColor greenColor]; [self.view addSubview:newView]; newView.translatesAutoresizingMaskIntoConstraints = NO; NSMutableArray *constraintArray = [NSMutableArray array]; [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView,self.view)]]; [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[newView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView,self.view)]]; [self.view addConstraints:constraintArray];
运行效果
示例
需求:以下所示
实现以下:
UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; UIView *yellow = [[UIView alloc]init]; yellow.backgroundColor = [UIColor yellowColor]; [self.view addSubview:yellow]; UIView *green = [[UIView alloc]init]; green.backgroundColor = [UIColor greenColor]; [self.view addSubview:green]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(0);// 使左边等于self.view的控件,间隔为0; make.top.equalTo(self.view.mas_top).offset(0); // 使顶部与self.view的控件的间隔为0; make.width.equalTo(self.view.mas_width).multipliedBy(0.5); // 设置宽度为self.view的一半,multipliedBy是倍数的意思,也就是,使宽度等于self.view宽度的0.5倍 make.height.equalTo(self.view.mas_height).multipliedBy(0.5);// 设置高度为self.view的一半。 }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等宽高 make.top.equalTo(redView.mas_top); // 与redview顶部对齐 make.leading.equalTo(redView.mas_right); // 与 redview的间隔为0 }]; [yellow mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等宽高 make.top.equalTo(redView.mas_bottom); // 与 redview的间隔为0 make.leading.equalTo(redView); // 与redvie左对齐 }]; [green mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(redView); // 跟redview等宽高 make.top.equalTo(yellow.mas_top); // 与yellow顶部对齐 make.leading.equalTo(yellow.mas_right); // 与 yellow的间隔为0
}];
PS:须要下载第三库 Masonry ,并导入 #import "Masonry.h"
Masonry 下的 Autolayout Animation
UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; UIView *greenView = [[UIView alloc]init]; greenView.backgroundColor = [UIColor greenColor]; [self.view addSubview:greenView]; self.greenView = greenView; UIView *blueView = [[UIView alloc]init]; blueView.backgroundColor = [UIColor blueColor]; [self.view addSubview:blueView]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view.mas_left).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(redView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(greenView.mas_right).offset(20); make.bottom.equalTo(self.view.mas_bottom).offset(-20); make.width.equalTo(self.view.mas_width).multipliedBy(0.2); make.height.equalTo(self.view.mas_height).multipliedBy(0.2); make.left.equalTo(redView.mas_right).offset(20).priority(250); }];
让咱们最后加几行代码,来实现这个动画吧!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //先把绿色方块从父视图上移除 [self.greenView removeFromSuperview]; //动画更新界面 [UIView animateWithDuration:1.0f animations:^{ [self.view layoutIfNeeded]; }]; }
运行效果
使用autolayout 利弊
autolayout有没有局限性和解决不了的问题?兼容性怎么样?效率怎么样