autolayout能够胜任ios xib autoresizingg mask无法完成的任务有哪些

屏幕适配(1)
AutoLayout
关于AutoLayout,最早从iOS6开始引入使用。
主要功能是使用约束,对视图进行相对布局,以适应不同屏尺的变换。
网上大量的资料都在介绍xib和storyboard,如何使用AutoLayout,说纯代码使用AutoLayout进行UI布局的越来越少。对于我这个习惯了代码UI布局的人,写个备忘:
AutoLayout是什么?
使用一句Apple的官方定义的话
AutoLayout是一种基于约束的,描述性的布局系统。 Auto Layout Is a Constraint-Based, Descriptive Layout System.
基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等
描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言(稍后会提到)的方法来进行描述
布局系统 - 即字面意思,用来负责界面的各个元素的位置。
总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini
iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。 总结
使用约束条件来描述布局,view的frame会依据这些约束来进行计算 Describe the layout with constraints, and frames are calculated automatically.
AutoLayout和Autoresizing Mask的区别
Autoresizing Mask是我们的老朋友了…如果你以前一直是代码写UI的话,你肯定写过UIViewAutoresizingFlexibleWidth之类的枚举;如果你以前用IB比较多的话,一定注意到过每个view的size
inspector中都有一个红色线条的Autoresizing的指示器和相应的动画缩放的示意图,这就是Autoresizing Mask。在iOS6之前,关于屏幕旋转的适配和iPhone,iPad屏幕的自动适配,基本都是由Autoresizing Mask来完成的。但是随着大家对iOS app的要求越来越高,以及已经以及今后可能出现的多种屏幕和分辨率的设备来说,Autoresizing Mask显得有些落伍和迟钝了。AutoLayout可以完成所有原来Autoresizing Mask能完成的工作,同时还能够胜任一些原来无法完成的任务,其中包括:
AutoLayout可以指定任意两个view的相对位置,而不需要像Autoresizing Mask那样需要两个view在直系的view hierarchy中。
AutoLayout不必须指定相等关系的约束,它可以指定非相等约束(大于或者小于等);而Autoresizing Mask所能做的布局只能是相等条件的。
AutoLayout可以指定约束的优先级,计算frame时将优先按照满足优先级高的条件进行计算。
Autoresizing Mask是AutoLayout的子集,任何可以用Autoresizing Mask完成的工作都可以用AutoLayout完成。AutoLayout还具备一些Autoresizing Mask不具备的优良特性,以帮助我们更方便地构建界面。
AutoLayout基本使用方法
Interface Builder
这部分网上大量的教程,都是说的这个
手动使用API添加约束
iOS6中新加入了一个类:NSLayoutConstraint,一个形如这样的约束
item1.attribute = multiplier ? item2.attribute + constant
对应的代码为
[NSLayoutConstraint
constraintWithItem:button
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&attribute:NSLayoutAttributeBottom
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&relatedBy:NSLayoutRelationEqua
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&toItem:superview
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&attribute:NSLayoutAttributeBottom
&&&&&&&&&&&&&&&&&&&&&&&&&&&&multiplier:1.0
<span style="color:#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&constant:-padding]
这对应的约束是“button的底部(y) = superview的底部 -10”。
在创建约束之后,需要将其添加到作用的view上。UIView(当然NSView也一样)加入了一个新的实例方法:
-(void)addConstraint:(NSLayoutConstraint *)
用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:
对于两个同层级view之间的约束关系,添加到他们的父view上
对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。这和CoreGraphic的-setNeedsDisplay一套东西是一样的~
Visual Format Language 可视&#26684;式语言
UIKit团队这次相当有爱,估计他们自己也觉得新加约束的API名字太长了,因此他们发明了一种新的方式来描述约束条件,十分有趣。这种语言是对视觉描述的一种抽象,大概过程看起来是这样的:
accept按钮在cancel按钮右侧默认间距处&
最后使用VFL(Visual Format Language)描述变成这样:
[NSLayoutConstraint
constraintsWithVisualFormat:@\\&[cancelButton]-[acceptButton]\&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&options:0
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&metrics:nil
<span style="color:#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&views:viewsDictionary];
其中viewsDictionary是绑定了view的名字和对象的字典,对于这个例子可以用以下方法得到对应的字典:
*cancelButton = ...
*acceptButton = ...
<span style="color:#
viewsDictionary
= NSDictionaryOfVariableBindings(cancelButton,acceptButton);
生成的字典为
{ acceptButton = &&; cancelButton = &&; }
当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。&在view名字后面添加括号以及连接处的数字可以赋予表达式更多意义,以下进行一些举例:
[cancelButton(72)]-12-[acceptButton(50)]
取消按钮宽72point,accept按钮宽50point,它们之间间距12point
[wideView(&=60@700)]
wideView宽度大于等于60point,该约束条件优先级为700(优先级最大&#20540;为1000,优先级越高的约束越先被满足)
V:[redBox][yellowBox(==redBox)]
竖直布局,先是一个redBox,其下方紧接一个宽度等于redBox宽度的yellowBox
H:|-[Find]-[FindNext]-[FindField(&=20)]-|
水平布局,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线'|‘ 表示superview的边缘)
容易出现的错误
因为涉及约束问题,因此约束模型下的所有可能出现的问题这里都会出现,具体来说包括两种:
Ambiguous Layout 布局不能确定
Unsatisfiable Constraints 无法满足约束
布局不能确定指的是给出的约束条件无法唯一确定一种布局,也即约束条件不足,无法得到唯一的布局结果。这种情况一般添加一些必要的约束或者调整优先级可以解决。无法满足约束的问题来源是有约束条件互相冲突,因此无法同时满足,需要删掉一些约束。两种错误在出现时均会导致布局的不稳定和错误,Ambiguous可以被容忍并且选择一种可行布局呈现在UI上,Unsatisfiable的话会无法得到UI布局并报错。
对于不能确定的布局,可以通过调试时暂停程序,在debugger中输入
po [[UIWindow keyWindow] _autolayoutTrace]
来检查是否存在Ambiguous Layout以及存在的位置,来帮助添加条件。另外还有一些检查方法,来查看view的约束和约束状态:
[view constraintsAffectingLayoutForOrientation/Axis: NSLayoutConstraintOrientationHorizontal/Vertical]
[view hasAmbiguousLayout]
[view exerciseAmbiguityInLayout]
动画是UI体验的重要部分,更改布局以后的动画也非常关键。说到动画,Core Animation又立功了..自从CA出现以后,所有的动画效果都非常cheap,在auto
layout中情况也和collection view里一样,很简单(可以参考),只需要把layoutIfNeeded放到animation
block中即可~
animateWithDuration:0.5 animations:^{
layoutIfNeeded];
<span style="color:#
纯净代码UI正常布局后,添加autolayout就可以了,调整相当方便
这是一段水平居中,垂直并列的4个按钮 布局代码
setTranslatesAutoresizingMaskIntoConstraints &是为no,开启AutoLayou.
&&&&//-----autoLayout
&&&&[_btn_1&setTranslatesAutoresizingMaskIntoConstraints:NO];
&&&&[_btn_2&setTranslatesAutoresizingMaskIntoConstraints:NO];
&&&&[_btn_3&setTranslatesAutoresizingMaskIntoConstraints:NO];
&&&&[_btn_4&setTranslatesAutoresizingMaskIntoConstraints:NO];
&&&&CGSize&winSize = [[iHappySDKSingle&shareSingle]&getScreenSize];
&&&&CGFloat&tpo =&_btn_1.frame.origin.y;
&&&&CGFloat&hpod =&_btn_1.frame.origin.x;
&&&&CGFloat&btnH =&_btn_1.frame.size.height;
&&&&CGFloat&vpod = winSize.width*0.15-btnH;
&&&&NSNumber* tp = [NSNumber&numberWithFloat:tpo];
&&&&NSNumber* hd = [NSNumber&numberWithFloat:hpod];
&&&&NSNumber* vd = [NSNumber&numberWithFloat:vpod];
&&&&NSNumber* bh = [NSNumber&numberWithFloat:btnH];
&&&&NSNumber* btm = [NSNumber&numberWithFloat:vpod*2];
&&&&NSDictionary&*dict1 =&NSDictionaryOfVariableBindings(_btn_1,_btn_2,_btn_3,_btn_4);
&&&&NSDictionary&*metrics =@{@&hPadding&:hd,@&vPadding&:vd,@&top&:tp,@&btm&:btm,@&btnHeight&:bh};
&&&&NSString&*vfl1 =&@&|-hPadding-[_btn_1]-hPadding-|&;
[self.view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl1
&&options:0
&&metrics:metrics
views:dict1]];
&&&&NSString&*vfl2 =&@&|-hPadding-[_btn_2]-hPadding-|&;
[self.view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl2
&&options:0
&&metrics:metrics
views:dict1]];
&&&&NSString&*vfl3 =&@&|-hPadding-[_btn_3]-hPadding-|&;
[self.view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl3
&&options:0
&&metrics:metrics
views:dict1]];
&&&&NSString&*vfl4 =&@&|-hPadding-[_btn_4]-hPadding-|&;
[self.view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl4
&&options:0
&&metrics:metrics
views:dict1]];
&&&&NSString&*vfl5 =&@&V:|-(&=top)-[_btn_1(btnHeight)]-vPadding-[_btn_2(btnHeight)]-vPadding-[_btn_3(btnHeight)]-vPadding-[_btn_4(btnHeight)]-(&=btm)-|&;
&&&&if&(_btn_1.hidden) {
&&&&&&&&vfl5 =&@&V:|-(&=top)-[_btn_2(btnHeight)]-vPadding-[_btn_3(btnHeight)]-vPadding-[_btn_4(btnHeight)]-(&=btm)-|&;
[self.view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl5
&&options:0
&&metrics:metrics
views:dict1]];
纯净代码UI正常布局后,增加一个函数,进行自动布局
水平居中布局:NSLayoutAttributeCenterX
垂直居中布局:NSLayoutAttributeCenterY
以及后面的布局切换动画。
- (void)setAutoLayoutForKuang:(UIView*)imgv
&&&&UIView&* view =&self;
&&&&[imgv&setTranslatesAutoresizingMaskIntoConstraints:NO];
&&&&NSDictionary&*dict1 =&NSDictionaryOfVariableBindings(imgv);
&&&&NSDictionary&*metrics =&@{@&width&:[NSNumbernumberWithFloat:imgv.frame.size.width],
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@&height&:[NSNumber&numberWithFloat:imgv.frame.size.height],
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@&top&:[NSNumber&numberWithFloat:imgv.frame.origin.y]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&};
&&&&NSString&*vfl1 =&@&[imgv(width)]&;
[view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl1
&&options:0
&&metrics:metrics
views:dict1]];
&&&&NSString&*vfl2 =&@&V:[imgv(height)]&;
[view&addConstraints:[NSLayoutConstraint&constraintsWithVisualFormat:vfl2
&&options:0
&&metrics:metrics
views:dict1]];
&&&&[view&addConstraint:[NSLayoutConstraint&constraintWithItem:imgvattribute:NSLayoutAttributeCenterX&relatedBy:NSLayoutRelationEqual
toItem:viewattribute:NSLayoutAttributeCenterX&multiplier:1&constant:0]];
&&&&[view&addConstraint:[NSLayoutConstraint&constraintWithItem:imgvattribute:NSLayoutAttributeCenterY&relatedBy:NSLayoutRelationEqual
toItem:viewattribute:NSLayoutAttributeCenterY&multiplier:1&constant:0]];
&&&&//animation
&&&&[UIView&animateWithDuration:0.25&animations:^{
&&&&&&&&[imgv&layoutIfNeeded];
-----------------------------------------
网上相关文章:
-----------------------------------------
1、&&&&推荐
2、&&&&&&此文包含有一个demo()
不是朋友在发愁手动些这些类&#20284;脚本的字符:
现在推荐一个开源库给大家
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5137次
排名:千里之外
原创:42篇1810人阅读
AutoLayout是什么?
使用一句Apple的官方定义的话
AutoLayout是一种基于约束的,描述性的布局系统。Auto Layout Is a Constraint-Based, Descriptive Layout System.
基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言(稍后会提到)的方法来进行描述布局系统 - 即字面意思,用来负责界面的各个元素的位置。
总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini
iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。总结
使用约束条件来描述布局,view的frame会依据这些约束来进行计算Describe the layout with constraints, and frames are calculated automatically.
AutoLayout和Autoresizing Mask的区别
Autoresizing Mask是我们的老朋友了…如果你以前一直是代码写UI的话,你肯定写过UIViewAutoresizingFlexibleWidth之类的枚举;如果你以前用IB比较多的话,一定注意到过每个view的size inspector中都有一个红色线条的Autoresizing的指示器和相应的动画缩放的示意图,这就是Autoresizing Mask。在iOS6之前,关于屏幕旋转的适配和iPhone,iPad屏幕的自动适配,基本都是由Autoresizing Mask来完成的。但是随着大家对iOS
app的要求越来越高,以及已经以及今后可能出现的多种屏幕和分辨率的设备来说,Autoresizing Mask显得有些落伍和迟钝了。AutoLayout可以完成所有原来Autoresizing Mask能完成的工作,同时还能够胜任一些原来无法完成的任务,其中包括:
AutoLayout可以指定任意两个view的相对位置,而不需要像Autoresizing Mask那样需要两个view在直系的view hierarchy中。AutoLayout不必须指定相等关系的约束,它可以指定非相等约束(大于或者小于等);而Autoresizing Mask所能做的布局只能是相等条件的。AutoLayout可以指定约束的优先级,计算frame时将优先按照满足优先级高的条件进行计算。
Autoresizing Mask是AutoLayout的子集,任何可以用Autoresizing Mask完成的工作都可以用AutoLayout完成。AutoLayout还具备一些Autoresizing Mask不具备的优良特性,以帮助我们更方便地构建界面。
AutoLayout基本使用方法
Interface Builder
最简单的使用方法是在IB中直接拖。在IB中任意一个view的File inspector下面,都有Use Autolayout的选择框(没有的同学可以考虑升级一下Xcode了=。=),钩上,然后按照平常那样拖控件就可以了。拖动控件后在左边的view hierarchy栏中会出现Constraints一向,其中就是所有的约束条件。
选中某个约束条件后,在右边的Attributes inspector中可以更改约束的条件,距离&#20540;和优先度等:
对于没有自动添加的约束,可以在IB中手动添加。选择需要添加约束的view,点击菜单的Edit-&Pin里的需要的选项,或者是点击IB主视图右下角的按钮,即可添加&#26684;外的约束条件。可视化的添加不仅很方便直观,而且基本不会出错,是优先推荐的添加约束的方式。但是有时候只靠IB是无法完成某些约束的添加的(比如跨view hierarchy的约束),有时候IB添加的约束不能满足要求,这时就需要使用约束的API进行补充。
手动使用API添加约束
iOS6中新加入了一个类:NSLayoutConstraint,一个形如这样的约束
item1.attribute = multiplier ? item2.attribute &#43; constant
对应的代码为
1 [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding]
这对应的约束是“button的底部(y) = superview的底部 -10”。
在创建约束之后,需要将其添加到作用的view上。UIView(当然NSView也一样)加入了一个新的实例方法:
-(void)addConstraint:(NSLayoutConstraint *)
用来将约束添加到view。在添加时唯一要注意的是添加的目标view要遵循以下规则:
对于两个同层级view之间的约束关系,添加到他们的父view上
对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
可以通过-setNeedsUpdateConstraints和-layoutIfNeeded两个方法来刷新约束的改变,使UIView重新布局。这和CoreGraphic的-setNeedsDisplay一套东西是一样的~
Visual Format Language 可视&#26684;式语言
UIKit团队这次相当有爱,估计他们自己也觉得新加约束的API名字太长了,因此他们发明了一种新的方式来描述约束条件,十分有趣。这种语言是对视觉描述的一种抽象,大概过程看起来是这样的:accept按钮在cancel按钮右侧默认间距处
最后使用VFL(Visual Format Language)描述变成这样:
1 [NSLayoutConstraint constraintsWithVisualFormat:@\\&[cancelButton]-[acceptButton]\\&
metrics:nil
views:viewsDictionary];
其中viewsDictionary是绑定了view的名字和对象的字典,对于这个例子可以用以下方法得到对应的字典:
1 UIButton *cancelButton = ...
2 UIButton *acceptButton = ...
3 viewsDictionary = NSDictionaryOfVariableBindings(cancelButton,acceptButton);
生成的字典为
{ acceptButton = &&; cancelButton = &&; }
当然,不嫌累的话自己手写也未尝不可。现在字典啊数组啊写法相对简化了很多了,因此也不复杂。关于Objective-C的新语法,可以参考我之前的一篇WWDC 2012笔记:。在view名字后面添加括号以及连接处的数字可以赋予表达式更多意义,以下进行一些举例:
[cancelButton(72)]-12-[acceptButton(50)]
取消按钮宽72point,accept按钮宽50point,它们之间间距12point
[wideView(&=60@700)]
wideView宽度大于等于60point,该约束条件优先级为700(优先级最大&#20540;为1000,优先级越高的约束越先被满足)
V:[redBox][yellowBox(==redBox)]
竖直布局,先是一个redBox,其下方紧接一个宽度等于redBox宽度的yellowBox
H:|-[Find]-[FindNext]-[FindField(&=20)]-|
水平布局,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线'|‘ 表示superview的边缘)
容易出现的错误
因为涉及约束问题,因此约束模型下的所有可能出现的问题这里都会出现,具体来说包括两种:
Ambiguous Layout 布局不能确定Unsatisfiable Constraints 无法满足约束
布局不能确定指的是给出的约束条件无法唯一确定一种布局,也即约束条件不足,无法得到唯一的布局结果。这种情况一般添加一些必要的约束或者调整优先级可以解决。无法满足约束的问题来源是有约束条件互相冲突,因此无法同时满足,需要删掉一些约束。两种错误在出现时均会导致布局的不稳定和错误,Ambiguous可以被容忍并且选择一种可行布局呈现在UI上,Unsatisfiable的话会无法得到UI布局并报错。对于不能确定的布局,可以通过调试时暂停程序,在debugger中输入
po [[UIWindow keyWindow] _autolayoutTrace]
来检查是否存在Ambiguous Layout以及存在的位置,来帮助添加条件。另外还有一些检查方法,来查看view的约束和约束状态:
[view constraintsAffectingLayoutForOrientation/Axis: NSLayoutConstraintOrientationHorizontal/Vertical][view hasAmbiguousLayout]
[view exerciseAmbiguityInLayout]
动画是UI体验的重要部分,更改布局以后的动画也非常关键。说到动画,Core Animation又立功了..自从CA出现以后,所有的动画效果都非常cheap,在auto layout中情况也和collection view里一样,很简单(可以参考),只需要把layoutIfNeeded放到animation
block中即可~
1 [UIView animateWithDuration:0.5 animations:^{
[view layoutIfNeeded];
如果对block不熟悉的话,可以看看我很早时候写的一篇。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:632457次
积分:5266
积分:5266
排名:第3518名
原创:15篇
转载:170篇
评论:52条
(1)(4)(1)(1)(3)(3)(25)(56)(49)(2)(4)(5)(4)(2)(1)(3)(2)(3)(6)(1)(1)(4)(4)Masonry介绍与使用 - 简书
下载简书移动应用
写了22591字,被3人关注,获得了4个喜欢
Masonry介绍与使用
MagicNumber -& autoresizingMask -& autolayout
以上是纯手写代码所经历的关于页面布局的三个时期
在iphone1-iphone3gs时代 window的size固定为(320,480) 我们只需要简单计算一下相对位置就好了
在iphone4-iphone4s时代 苹果推出了retina屏 但是给了码农们非常大的福利:window的size不变
在iphone5-iphone5s时代 window的size变了(320,568) 这时autoresizingMask派上了用场(为啥这时候不用Autolayout? 因为还要支持ios5呗) 简单的适配一下即可
在iphone6+时代 window的width也发生了变化(相对5和5s的屏幕比例没有变化) 终于是时候抛弃autoresizingMask改用autolayout了(不用支持ios5了 相对于屏幕适配的多样性来说autoresizingMask也已经过时了)
学习Masonry的之前必须具备一些autolayout的基本知识,接下来简单介绍一下autolayout.
Autolayout
AutoLayout是什么?
AutoLayout是一种基于约束的,描述性的布局系统。
基于约束 - 和以往定义frame的位置和尺寸不同,AutoLayout的位置确定是以所谓相对位置的约束来定义的,比如x坐标为superView的中心,y坐标为屏幕底部上方10像素等
描述性 - 约束的定义和各个view的关系使用接近自然语言或者可视化语言的方法来进行描述
布局系统 - 即字面意思,用来负责界面的各个元素的位置。
总而言之,AutoLayout为开发者提供了一种不同于传统对于UI元素位置指定的布局方法。以前,不论是在IB里拖放,还是在代码中写,每个UIView都会有自己的frame属性,来定义其在当前视图中的位置和尺寸。使用AutoLayout的话,就变为了使用约束条件来定义view的位置和尺寸。这样的最大好处是一举解决了不同分辨率和屏幕尺寸下view的适配问题,另外也简化了旋转时view的位置的定义,原来在底部之上10像素居中的view,不论在旋转屏幕或是更换设备(iPad或者iPhone5或者以后可能出现的mini iPad)的时候,始终还在底部之上10像素居中的位置,不会发生变化。
AutoLayout和Autoresizing Mask的区别:
Autoresizing Mask是我们的老朋友了…如果你以前一直是代码写UI的话,你肯定写过UIViewAutoresizingFlexibleWidth之类的枚举;如果你以前用IB比较多的话,一定注意到过每个view的size inspector中都有一个红色线条的Autoresizing的指示器和相应的动画缩放的示意图,这就是Autoresizing Mask。在iOS6之前,关于屏幕旋转的适配和iPhone,iPad屏幕的自动适配,基本都是由Autoresizing Mask来完成的。但是随着大家对iOS app的要求越来越高,以及已经以及今后可能出现的多种屏幕和分辨率的设备来说,Autoresizing Mask显得有些落伍和迟钝了。
AutoLayout可以完成所有原来Autoresizing Mask能完成的工作,同时还能够胜任一些原来无法完成的任务,其中包括:
AutoLayout可以指定任意两个view的相对位置,而不需要像Autoresizing Mask那样需要两个view在直系的view hierarchy中。
AutoLayout不必须指定相等关系的约束,它可以指定非相等约束(大于或者小于等);而Autoresizing Mask所能做的布局只能是相等条件的。
AutoLayout可以指定约束的优先级,计算frame时将优先按照满足优先级高的条件进行计算。
Autoresizing Mask是AutoLayout的子集,任何可以用Autoresizing Mask完成的工作都可以用AutoLayout完成。AutoLayout还具备一些Autoresizing Mask不具备的优良特性,以帮助我们更方便地构建界面。
设置frame、Autoresizing Mask、Autolayout区别:
Autoresizing
Autolayout
用autolayout之前,我们可能这样写“button在左上角,坐标为(20,230)”,现在用相对语言代替绝对,可能会这样写“button相对于父视图垂直居中,并且距父视图左边缘10个像素”。
接下正式介绍今天的主角Masonry
Masonry介绍
是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性 而且同时支持 iOS 和 Max OS X
我们先来看一段官方的sample code来认识一下
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
看到block里面的那句话: make edges equalTo superview with insets通过链式的自然语言 就把view1给autolayout好了 是不是简单易懂?
为什么使用Masonry
先上一段官方api写法代码:
UIView *superview =
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
这段代码告诉你 我创建了一个比self.view小了一圈的view。再来看看使用Masonry的代码:
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
或者更简洁:
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
结果还用我说嘛,啦啦啦 。
Masonry使用
看一下支持哪一些属性:
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *
这些属性与NSLayoutAttrubute的对照表如下:
NSAutoLayout
NSLayoutAttributeLeft
NSLayoutAttributeTop
NSLayoutAttributeRight
NSLayoutAttributeBottom
NSLayoutAttributeLeading
NSLayoutAttributeTrailing
NSLayoutAttributeWidth
NSLayoutAttributeHeight
NSLayoutAttributeCenterX
NSLayoutAttributeCenterY
NSLayoutAttributeBaseline
其中leading与left trailing与right 在正常情况下是等价的 但是当一些布局是从右至左时(比如阿拉伯文?没有类似的经验) 则会对调 换句话说就是基本可以不理不用 用left和right就好了
在ios8发布后 又新增了一堆奇奇怪怪的属性(有兴趣的朋友可以去瞅瞅) 暂时还不支持(不过你要支持ios6,ios7 就没必要去管那么多了)
比较约束方法如下:
.equalTo equivalent to NSLayoutRelationEqual
.lessThanOrEqualTo equivalent to NSLayoutRelationLessThanOrEqual
.greaterThanOrEqualTo equivalent to NSLayoutRelationGreaterThanOrEqual
这三个等式约束需要接受一个参数,它可以是任何如下:
1.MASViewAttribute
make.centerX.lessThanOrEqualTo(view2.mas_left);
MASViewAttribute
NSLayoutAttribute
view.mas_left
NSLayoutAttributeLeft
view.mas_right
NSLayoutAttributeRight
view.mas_top
NSLayoutAttributeTop
view.mas_bottom
NSLayoutAttributeBottom
view.mas_leading
NSLayoutAttributeLeading
view.mas_trailing
NSLayoutAttributeTrailing
view.mas_width
NSLayoutAttributeWidth
view.mas_height
NSLayoutAttributeHeight
view.mas_centerX
NSLayoutAttributeCenterX
view.mas_centerY
NSLayoutAttributeCenterY
view.mas_baseline
NSLayoutAttributeBaseline
2.UIView/NSView
如果你想要的观点。大于或等于label.left:
//these two constraints are exactly the same
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);
3.NSNumber
自动布局允许宽度和高度设置为常量值。如果你想设置视图有一个最小和最大宽度可以通过平等的块的数量:
//width &= 200 && width &= 400
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)
然而自动布局不允许对齐属性,如left,right,centerY等被设置为常量值。所以如果你通过这些属性砌体NSNumber将把这些变成约束相对于视图的父视图即:
//creates view.left = view.superview.left + 10
make.left.lessThanOrEqualTo(@10)
对NSNumber你还可以使用结构体去构建你的约束:
make.top.mas_equalTo(42);
make.height.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(50, 100));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 0, 10, 0));
make.left.mas_equalTo(view).mas_offset(UIEdgeInsetsMake(10, 0, 10, 0));
make.height.equalTo(@[view1.mas_height, view2.mas_height]);
make.height.equalTo(@[view1, view2]);
make.left.equalTo(@[view1, @100, view3.right]);
优先级属性:
.priority allows you to specify an exact priority
.priorityHigh equivalent to UILayoutPriorityDefaultHigh
.priorityMedium is half way between high and low
.priorityLow equivalent to UILayoutPriorityDefaultLow
优先级是可以附加约束链的结束位置:
make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();
make.top.equalTo(label.mas_top).with.priority(600);
组合属性:
为了方便使用,Masonry也提供了几个方法,可以同时创建多个约束。这些被称为MASCompositeConstraints。
edges(边界):
// make top, left, bottom, right equal view2
make.edges.equalTo(view2);
// make top = superview.top + 5, left = superview.left + 10,
bottom = superview.bottom - 15, right = superview.right - 20
make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20))
size(尺寸):
// make width and height greater than or equal to titleLabel
make.size.greaterThanOrEqualTo(titleLabel)
// make width = superview.width + 100, height = superview.height - 50
make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))
center(中心):
// make centerX and centerY = button1
make.center.equalTo(button1)
// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))
你可以链接视图属性增加可读性:
// All edges but the top should equal those of the superview
make.left.right.and.bottom.equalTo(superview);
make.top.equalTo(otherView);
有时你需要修改现有的约束,添加动画或删除/替换约束。Masonry有几种不同的方法来更新约束。
1.mas_makeConstraints:
你可以坚持一个引用特定约束条件的约束使表达式的结果分配给一个局部变量或一个类属性。你也可以引用多个约束将它们存储在一个数组中。
// in public/private interface
@property (nonatomic, strong) MASConstraint *topC
// when making constraints
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
self.topConstraint = make.top.equalTo(superview.mas_top).with.offset(padding.top);
make.left.equalTo(superview.mas_left).with.offset(padding.left);
// then later you can call
[self.topConstraint uninstall];
2.mas_updateConstraints
更新约束:
// this is Apple's recommended place for adding/updating constraints
// this method can get called multiple times in response to setNeedsUpdateConstraints
// which can be called by UIKit internally or in your code if you need to trigger an update to your constraints
- (void)updateConstraints {
[self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.width.equalTo(@(self.buttonSize.width)).priorityLow();
make.height.equalTo(@(self.buttonSize.height)).priorityLow();
make.width.lessThanOrEqualTo(self);
make.height.lessThanOrEqualTo(self);
//according to apple super should be called at end of method
[super updateViewConstraints];
3.mas_remakeConstraints
mas_remakeConstraints会删除之前的所有约束重新添加:
- (void)changeButtonPosition {
[self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(self.buttonSize);
if (topLeft) {
make.top.and.left.offset(10);
make.bottom.and.right.offset(-10);
好了下面可以进入正题(为了方便 我们测试的superView都是一个size为(300,300)的UIView)
通过一些简单的实例来简单介绍如何轻松愉快的使用:
1. [基础] 居中显示一个view
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view.
UIView *sv = [UIView new];
[sv showPlaceHolder];
sv.backgroundColor = [UIColor blackColor];
[self.view addSubview:sv];
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(300, 300));
那么先看看这几行代码
//从此以后基本可以抛弃CGRectMake了
UIView *sv = [UIView new];
//在做autoLayout之前 一定要先将view添加到superview上 否则会报错
[self.view addSubview:sv];
//mas_makeConstraints就是Masonry的autolayout添加函数 将所需的约束添加到block中行了
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
//将sv居中(很容易理解吧?)
make.center.equalTo(self.view);
//将size设置成(300,300)
make.size.mas_equalTo(CGSizeMake(300, 300));
这里有两个问题要分解一下:
1、首先在Masonry中能够添加autolayout约束有三个函数
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))
mas_makeConstraints 只负责新增约束 Autolayout不能同时存在两条针对于同一对象的约束 否则会报错
mas_updateConstraints 针对上面的情况 会更新在block中出现的约束 不会导致出现两个相同约束的情况
mas_remakeConstraints 则会清除之前的所有约束 仅保留最新的约束
三种函数善加利用 就可以应对各种情况了
2、其次 equalTo 和 mas_equalTo的区别在哪里呢? 其实 mas_equalTo是一个MACRO
#define mas_equalTo(...)
equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...)
greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...)
lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_offset(...)
valueOffset(MASBoxValue((__VA_ARGS__)))
可以看到 mas_equalTo只是对其参数进行了一个BOX操作(装箱) MASBoxValue的定义具体可以看看源代码 太长就不贴出来了
所支持的类型 除了NSNumber支持的那些数值类型之外 就只支持CGPoint CGSize UIEdgeInsets
介绍完这几个问题 我们就继续往下了 PS:刚才定义的sv会成为我们接下来所有sample的superView
2. [初级] 让一个view略小于其superView(边距为10)
UIView *sv1 = [UIView new];
[sv1 showPlaceHolder];
sv1.backgroundColor = [UIColor redColor];
[sv addSubview:sv1];
[sv1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
make.top.equalTo(sv).with.offset(10);
make.left.equalTo(sv).with.offset(10);
make.bottom.equalTo(sv).with.offset(-10);
make.right.equalTo(sv).with.offset(-10);
/* 也等价于
make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
可以看到 edges 其实就是top,left,bottom,right的一个简化 分开写也可以 一句话更省事
那么为什么bottom和right里的offset是负数呢? 因为这里计算的是绝对的数值 计算的bottom需要小于sv的底部高度 所以要-10 同理用于right
这里有意思的地方是and和with 其实这两个函数什么事情都没做
- (MASConstraint *)with {
- (MASConstraint *)and {
但是用在这种链式语法中 就非常的巧妙和易懂 不得不佩服作者的心思(虽然我现在基本都会省略)
3. [初级] 让两个高度为150的view垂直居中且等宽且等间隔排列 间隔为10(自动计算其宽度)
int padding1 = 10;
[sv2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(sv.mas_centerY);
make.left.equalTo(sv.mas_left).with.offset(padding1);
make.right.equalTo(sv3.mas_left).with.offset(-padding1);
make.height.mas_equalTo(@150);
make.width.equalTo(sv3);
[sv3 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(sv.mas_centerY);
make.left.equalTo(sv2.mas_right).with.offset(padding1);
make.right.equalTo(sv.mas_right).with.offset(-padding1);
make.height.mas_equalTo(@150);
make.width.equalTo(sv2);
4. [中级] 在UIScrollView顺序排列一些view并自动计算contentSize
UIScrollView *scrollView = [UIScrollView new];
scrollView.backgroundColor = [UIColor whiteColor];
[sv addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(5,5,5,5));
UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(scrollView);
make.width.equalTo(scrollView);
int count = 10;
UIView *lastView =
for ( int i = 1 ; i &= ++i )
UIView *subv = [UIView new];
[container addSubview:subv];
subv.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )
saturation:( arc4random() % 128 / 256.0 ) + 0.5
brightness:( arc4random() % 128 / 256.0 ) + 0.5
[subv mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.and.right.equalTo(container);
make.height.mas_equalTo(@(20*i));
if ( lastView )
make.top.mas_equalTo(lastView.mas_bottom);
make.top.mas_equalTo(container.mas_top);
lastView =
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(lastView.mas_bottom);
从scrollView的scrollIndicator可以看出 scrollView的内部已如我们所想排列好了
这里的关键就在于container这个view起到了一个中间层的作用 能够自动的计算uiscrollView的contentSize
5. [高级] 横向或者纵向等间隙的排列一组view
很遗憾 autoLayout并没有直接提供等间隙排列的方法(Masonry的官方demo中也没有对应的案例) 但是参考案例3 我们可以通过一个小技巧来实现这个目的 为此我写了一个Category
@implementation UIView(Masonry_LJC)
- (void) distributeSpacingHorizontallyWith:(NSArray*)views
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
for ( int i = 0 ; i & views.count+1 ; ++i )
UIView *v = [UIView new];
[spaces addObject:v];
[self addSubview:v];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(v.mas_height);
UIView *v0 = spaces[0];
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left);
make.centerY.equalTo(((UIView*)views[0]).mas_centerY);
UIView *lastSpace = v0;
for ( int i = 0 ; i & views. ++i )
UIView *obj = views[i];
UIView *space = spaces[i+1];
[obj mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(lastSpace.mas_right);
[space mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(obj.mas_right);
make.centerY.equalTo(obj.mas_centerY);
make.width.equalTo(v0);
lastSpace =
[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.mas_right);
- (void) distributeSpacingVerticallyWith:(NSArray*)views
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
for ( int i = 0 ; i & views.count+1 ; ++i )
UIView *v = [UIView new];
[spaces addObject:v];
[self addSubview:v];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(v.mas_height);
UIView *v0 = spaces[0];
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_top);
make.centerX.equalTo(((UIView*)views[0]).mas_centerX);
UIView *lastSpace = v0;
for ( int i = 0 ; i & views. ++i )
UIView *obj = views[i];
UIView *space = spaces[i+1];
[obj mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(lastSpace.mas_bottom);
[space mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(obj.mas_bottom);
make.centerX.equalTo(obj.mas_centerX);
make.height.equalTo(v0);
lastSpace =
[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_bottom);
简单的来测试一下
UIView *sv11 = [UIView new];
UIView *sv12 = [UIView new];
UIView *sv13 = [UIView new];
UIView *sv21 = [UIView new];
UIView *sv31 = [UIView new];
sv11.backgroundColor = [UIColor redColor];
sv12.backgroundColor = [UIColor redColor];
sv13.backgroundColor = [UIColor redColor];
sv21.backgroundColor = [UIColor redColor];
sv31.backgroundColor = [UIColor redColor];
[sv addSubview:sv11];
[sv addSubview:sv12];
[sv addSubview:sv13];
[sv addSubview:sv21];
[sv addSubview:sv31];
//给予不同的大小 测试效果
[sv11 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(@[sv12,sv13]);
make.centerX.equalTo(@[sv21,sv31]);
make.size.mas_equalTo(CGSizeMake(40, 40));
[sv12 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(70, 20));
[sv13 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(50, 50));
[sv21 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(50, 20));
[sv31 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(40, 60));
[sv distributeSpacingHorizontallyWith:@[sv11,sv12,sv13]];
[sv distributeSpacingVerticallyWith:@[sv11,sv21,sv31]];
[sv showPlaceHolderWithAllSubviews];
[sv hidePlaceHolder];
perfect! 简洁明了的达到了我们所要的效果
这里所用的技巧就是 使用空白的占位view来填充我们目标view的旁边 这点通过图上的空白标注可以看出来
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:}

我要回帖

更多关于 iosautoresizingmask 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信