Auto Layout深刻理解,及masonry简单介绍

本篇博客是本人在学习本身主动布局过程当中对本身主动布局的理解和整理,分三部分介绍,内容可能会有所反复。见谅。html


1、autosizing与Auto Layout对照,及Auto Layout简单介绍

1springs&struts简单介绍及问题ios

你确定很是熟悉autosizing masks-也被以为是springs&struts模式。autosizing mask决定了当一个视图的父视图大小改变时,其自身需要作出什么改变。它有一个灵活的或固定不变的marginsstruts)吗?它的宽和高要作出什么改变(springs)?git

但是毕竟不像本身主动布局同样对所有视图进行全面约束,在某些状况下的不能依照开发人员的意愿完美的布局视图,好比http://www.cocoachina.com/industry/20131203/7462.html中第一个样例就是autosizing布局失败的样例,此时需要在viewWillLayoutSubviews中依据设备方向对frame进行设定,但是适配是一个使人很烦躁的事情。稍不注意就会出错,因此产生了后来的本身主动布局。github

二、本身主动布局简单介绍及优点spring

本身主动布局使用约束去说明视图间的布局状况,使用约束最大的优点就是你不再需要把时间浪费在坐标上了。数组

相反,你可以向本身主动布局描写叙述视图怎样和其它视图相关联,本身主动布局将会为你完毕所有困难的工做。这叫作依据目的设计(designing by intent)。app

当你依据目的设计时,你表达的是你想要实现什么,而不需要关心它怎样实现。在autosizing中咱们描写叙述布局时说”button的左上角坐标为(20230",现在你可以这么说了:”button是垂直居中于它的父视图。并且相对于父视图的左边缘有一个固定的距离”,使用这个描写叙述。不管父视图多大或多小,本身主动布局都可以本身主动计算出你的button需要在哪儿出现。这使得你用户界面的设置更具描写叙述性.你仅仅需简单的定义约束。系统会为你本身主动计算framesless

使用本身主动布局还有一个重要的优势就是本地化。iphone

比方德语中的文本。出了名的比老奶奶的裹脚布还要长。适配起来是一件很是麻烦的事。再次。本身主动布局解救了猿,因为它能依据label需要显示的内容本身主动改变label的大小。函数

本身主动布局不只对旋转有做用。它还能轻易的缩放你UI的大小从而适应不一样尺寸的屏幕。

好比iphone5比iphone4s的高度变高了,程序在iPhone5中显示时是否会出现故障呢。不用操心。本身主动布局能轻易的拉伸你程序的用户界面。从而充满iPhone5垂直方向上多出来的空间。

注意:标示本身主动布局是否有效的T-bars是橘黄色时,意味着你的布局没有完毕,即本身主动布局没有足够的约束条件计算出视图的位置和大小。解决的方法即是添加不少其它约束,直到他们变蓝。

三、拥抱约束

1)、本身主动约束

假设你根本不提供不论什么约束,Xcode本身主动分配一套默认的约束,正是咱们所知的本身主动约束。它会在程序built的编译时间中去完毕这些事。而不是设计时间。

当你设计你的用户界面时,Xcode5中的本身主动布局为了避免參与你的设计方法而努力工做,这这是咱们喜欢它的缘由。本身主动约束为你的视图提供一个固定尺寸和位置。换句话说,视图老是拥有跟你在storyboard中看到的同样的坐标。这是很方便的,因为这就意味着你可以大量的忽视本身主动布局。你可以为那些拥有充分约束的控件不添加约束,仅仅为那些需要特殊规则的视图建立约束。

2)、Xcode建立本身主动约束的规则

Xcode仅仅为那些你没有设置不论什么约束的对象建立本身主动约束。

一旦你添加一个约束。你即是告诉Xcode你接管了这个视图。

Xcode将再也不添加不论什么本身主动约束,并但愿你为这个视图添加需要的约束。

3)、不完整约束的影响(约束过多或不足)

尽管Xcode5之后不再强制你老是有一个有效的布局,但是执行一个无效布局的程序是不明智的,因为本身主动布局可能不能正确的计算需要将视图放在哪儿,要么视图的位置是不可预知的(约束不够)。要么程序将会崩溃(约束过多)。

4)、错位的视图

错位的视图,即依据本身主动布局显示视图的frame和你在屏幕上放置的视图的frame不在同一位置。此时依据本身主动布局显示视图的frame是橙色的虚线边框,你在屏幕上放置的视图的frame是橙色的实线边框(当谈到本身主动布局。橙色表明坏的)。

====假设你在屏幕上放置的视图的frame是你想要的位置,此时点击Editor菜单->Resolve Auto Layout Issues菜单->Update Constraints就可以更新约束

2、本身主动布局介绍,及为什么引入masonry

说明:在xib和storyboard中由于苹果将约束可视化呈现给开发人员使得本身主动布局很是easy使用;经过代码构建界面时假设想使用本身主动布局就必须经过苹果提供的接口建立约束。由于本身主动布局的接口不易使用。因此就产生了masonry,masonry将苹果提供的本身主动布局接口封装的易于使用。

1Auto Layout是什么

Auto Layout是一个基于constraint(约束)的布局系统。它依据UI元素之间约束关系来调整UI元素的位置和大小。

2Auto Layout解决什么问题

  • 更easy适配不一样分辨率设备的屏幕(iPhone 6 Plus, iPhone 6, iPhone 5s/5, iPhone 4s/4)
  • 当设备旋转时不需要作额外处理
  • 使用constraint来描写叙述布局逻辑,更利于理解和清晰

三、代码中怎样使用Auto Layout

Auto Layout中约束的类相应是NSLayoutConstraint而建立NSLayoutConstraint对象主要有两种方式,第一种是

+ (id)constraintWithItem:(id)view1

               attribute:(NSLayoutAttribute)attribute1

               relatedBy:(NSLayoutRelation)relation

                  toItem:(id)view2

               attribute:(NSLayoutAttribute)attribute2

              multiplier:(CGFloat)multiplier

                constant:(CGFloat)constant;

上面方法主要意思是,某个view1attribute1等于(小于或等于/大于或等于)某个view2attribute2multiplier倍加上constant

而attribute主要由表示位置(///)和大小(/)的下面几个值:

typedef enum: NSInteger {

   NSLayoutAttributeLeft = 1,

   NSLayoutAttributeRight,

   NSLayoutAttributeTop,

   NSLayoutAttributeBottom,

   NSLayoutAttributeLeading,

   NSLayoutAttributeTrailing,

   NSLayoutAttributeWidth,

   NSLayoutAttributeHeight,

   NSLayoutAttributeCenterX,

   NSLayoutAttributeCenterY,

   NSLayoutAttributeBaseline,

   NSLayoutAttributeNotAnAttribute = 0

} NSLayoutAttribute;

简化一下。使用公式可以表达为:

view1.attribute1 = view2.attribute2 * multiplier + constant

另一种方式是:

+ (NSArray *)constraintsWithVisualFormat:(NSString *)format 

                                 options:(NSLayoutFormatOptions)opts 

                                 metrics:(NSDictionary *)metrics 

                                   views:(NSDictionary *)views;

这样的方式主要是採用Visual Format Language(可视化格式语言)来描写叙述约束布局。尽管语法比較简洁。但是可读性比較差和easy出错。

4Auto Layout存在问题

尽管Auto Layout在布局view方面是很强大和灵活,但是建立constraint的语法过于繁杂,引用Masonry一个样例:

UIView *superview = self;


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],


 ]];

如此简单的一个样例都要编写这么多行代码。想象一下假设建立多个viewconstraint时会多么痛苦啊。

还有一个方式是採用Visual Format Language (VFL),尽管语法比較简洁,但是可读性比較差和easy出错。

五、为何使用Masonry

Masonry是採用链式DSL(Domain-specific language)来封装NSLayoutConstraint,经过这样的方式编写Auto Layout布局代码更加易读和简洁。

六、Masonry怎样使用

使用Masonry建立constraint来定义布局的方式有三种:mas_makeConstraintsmas_updateConstraintsmas_remakeConstraints

1. mas_makeConstraints

使用mas_makeConstraints建立constraint后,你可以使用局部变量或属性来保存以便下次引用它;假设建立多个constraints,你可以採用数组来保存它们。

// in public/private interface

@property (nonatomic, strong) MASConstraint *topConstraint;


...


// 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

有时你需要更新constraint(好比,动画和调试)而不是建立固定constraint,可以使用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 updateConstraints];

}

3. mas_remakeConstraints

mas_remakeConstraintsmas_updateConstraints比較类似,都是更新constraint。只是。mas_remakeConstraints是删除以前constraint。而后再加入新的constraint(适用于移动动画);而mas_updateConstraints仅仅是更新constraint的值。

- (void)changeButtonPosition {

    [self.button mas_remakeConstraints:^(MASConstraintMaker *make) {

        make.size.equalTo(self.buttonSize);


        if (topLeft) {

            make.top.and.left.offset(10);

        } else {

            make.bottom.and.right.offset(-10);

        }

    }];

}

想了解以上三个代码片断的不少其它细节,可以下载Masonry iOS Examplesproject查阅。

七、masonry使用举例

1)、三个控件等高

     make.height.mas_equalTo(@[redView, blueView]);

2)、让控件始终居中显示

make.center.mas_equalTo(self.view);

3)、设置约束的优先级为最低

make.width.height.mas_equalTo(100 * self.scacle).priorityLow();

4)、让控件的宽和高小于或者等于self.view的宽和高

make.width.height.lessThanOrEqualTo(self.view);

八、此外本身主动布局的第三方库还有Classy。由于没实用过,就再也不叙述了。有兴趣的话可以參考http://blog.csdn.net/zhang_red/article/details/45503683,或者谷歌一下。

3、Auto Layout使用总结

一、本身主动布局常用函数

1)、setNeedsUpdateConstraints

当一个本身定义view的某个属性发生改变。并且可能影响到constraint时,需要调用此方法去标记constraints需要在将来的某个点更新。系统而后调用updateConstraints.

2)、needsUpdateConstraints

constraint-based layout system使用此返回值去决定是否需要调用updateConstraints做为正常布局过程的一部分。

3)、updateConstraintsIfNeeded

立刻触发约束更新。本身主动更新布局。

4)、updateConstraints

本身定义view应该重写此方法在当中创建constraints. 注意:要在实现在最后调用[super updateConstraints]

5)、updateViewConstraints

本身定义UIViewcontroller应该重写此方法在当中创建constraints. 注意:要在实现在最后调用[super updateConstraints]

2、要使用AutoLayout,请先设置要约束的viewtranslatesAutoresizingMaskIntoConstraints 属性为 NO 

在xib或者sb中勾选Use Auto Layout。所有在xib或者sb中出现的view都已经默认将translatesAutoresizingMaskIntoConstraints设置为NO

3、在使用AutoLayout布局的view中,代码中避免出现设置其frame相关属性(如center)的代码 ,但是可以获取其frame

4、经过代码为xibsbview添加约束时。尽可能避免在 viewDidLoad中运行,最好放在updateViewConstraints[UIViewcontroller]或者updateConstraints[UIView] ,记得调用[super updateViewConstraints]或者[super updateConstraints];

注意:在updateViewConstraintsview加入约束,请确保该viewtranslatesAutoresizingMaskIntoConstraints属性已设置为NO假设你真的写在viewDidLoad里了。那么可能会遇到这样的崩溃错误Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Impossible to set up layout with view hierarchy unprepared for constraint.'

5 假设需要在控制器中动态加入或者移除视图,在控制器中为新加入的视图添加约束,在updateViewConstrains中实现,而后调用[super updateViewConstrains];同理,在view中动态加入或者移除视图。在updateConstrains中实现,而后调用[super updateConstrains]

6 控制器在其view需要又一次布局时会运行下面过程:

 控制器的视图调整到新的尺寸 - 控制器会依据当前状态栏、导航条等其余因素的状态来调整其view的位置尺寸

 假设没有使用autolayout,所有子视图会依据autoresizeing mask调整

 调用viewWillLayoutSubviews

 调用控制器视图的layoutSubviews,假设是使用autolayout,则会调用updateViewConstrains -> 该方法的实现会调用所有子视图的updateConstraints -> 更新完约束以后,所有视图会依据计算出来的新的布局更新位置

 调用控制器的viewDidLayoutSubviews

7、本身定义view需要又一次布局时会运行下面过程:

与使用springs and struts(autoresizingMask)比較。Auto layoutview显示以前。多引入了两个步骤:updating constraints laying out views

每一个步骤都依赖于上一个。display依赖layout,而layout依赖updating constraints

 updating constraints->layout->display

第一步:updating constraints。被称为測量阶段。其从下向上(from subview to super view),为下一步layout准备信息。

可以经过调用方法setNeedUpdateConstraints去触发此步。

constraints的改变也会本身主动的触发此步。但是,当你本身定义view的时候。假设一些改变可能会影响到布局的时候。一般需要本身去通知Auto layoutupdateConstraintsIfNeeded

本身定义view的话,一般可以重写updateConstraints方法。在当中可以加入view需要的局部的contraints

第二步:layout,其从上向下(from super view to subview),此步主要应用上一步的信息去设置viewcenterbounds。可以经过调用setNeedsLayout去触发此步骤。此方法不会立刻应用layout。假设想要系统立刻的更新layout,可以调用layoutIfNeeded。另外。本身定义view可以重写方法layoutSubViews来在layout的project中获得不少其它的定制化效果。

第三步:display,此步时把view渲染到屏幕上,它与你是否使用Auto layout无关。其操做是从上向下(from super view to subview),经过调用setNeedsDisplay触发。

因为每一步都依赖前一步,所以一个display可能会触发layout。当有不论什么layout没有被处理的时候,同理,layout可能会触发updating constraints,当constraint system更新改变的时候。

需要注意的是。这三步不是单向的。constraint-based layout是一个迭代的过程。layout过程当中,可能去改变constraints,有一次触发updating constraints。进行一轮layout过程。

注意:假设你每一次调用本身定义layoutSubviews都会致使还有一个布局传递,那么你将会陷入一个无限循环中。

相关文章
相关标签/搜索