AutoLayout & Masonry 小结

AutoLayout

AutoLayout是基于约束的描述性的布局系统

官方文档:

https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1

概念

AutoLayout的核心观念就是从基于frame的布局转换到基于约束的布局。

基于frame的布局,frame based layout,根据相对坐标原点的位置来布局:

基于约束的布局,Constraint based layout:

约束公式

翻译过来就是item1的某个属性和item2的某个属性乘以倍数加常数有某种关系

约束属性

约束分类

按照item数目:一元约束,二元约束

按照约束属性的作用:大小约束,位置约束(水平约束,垂直约束)

约束准则

大小属性不能约束位置属性。反之也是

常数值不能约束位置属性。

非1倍数不能作用于位置属性。

水平属性不能约束垂直属性,反之也是

Leading/Trailing属性不能约束Left/Right属性

约束关系

等于,小于或等于,大于或等于

创建约束

 xib创建:

https://github.com/cooop/iOSDemo/tree/master/AutoLayoutDemo

代码创建:

步骤:创建一个约束,将约束添加到合适的view上,重复以上得到一个可满足的无歧义的约束

[NSLayoutConstraint constraintWithItem:redView

                                                    attribute:NSLayoutAttributeLeading

                                                 relatedBy:NSLayoutRelationEqual

                                                      toItem:blueView

                                                   attribute:NSLayoutAttributeTrailing

                                                  multiplier:1.0

                                                   constant:8];

将约束添加到合适的view上

一元约束,放在item上

二元约束,原则找两个item的最近公共祖先

API:[view addConstraint:constraint];

[view removeConstraint:constraint];

重复以上得到一个可满足的无歧义的约束:

AutoLayout的终极目标就是得到可满足无歧义的布局解决方案,需要item在水平垂直两个方向各至少需要两个约束

不可满足的约束,在一个方向上缺少约束,使得item在改方向上布局不能确定,会有隐式的布局问题

冲突约束,在一个方向上,item含有两个以上约束,且约束不能同时满足,系统会丢弃冲突约束,选择一个满足的解决方案,也会有隐式的布局问题

解决歧义

优先级:范围1-1000,数值越大优先级越高,优先级高的约束率先满足。默认约束都是Required的(最高优先级),所以不要以为优先级设为DefaultHight就很高了,还没有不设来的高,正确的做法是把其他冲突的约束的优先级设置低。

Required = 1000

DefaultHight = 750

DefaultLow = 250

FittingSizeLevel = 50

constraint.priority = 1000

constraint.priority = UILayoutPriorityRequired

内在大小 Intrinsic Content Size

有一些view有一个内在的大小,例如UILabel设置完字体和文字,就有一个内在宽度和高度恰好包裹文字。UIImage如果有图片,内在宽度和高度与图片大小一致。

如果有内在宽度,在水平方向上可以少设置一个约束;如果有内在高度,在垂直方向上可以少设置一个约束。即UILabel只需要设置left和top两个约束就可以可满足。

view的content hugging和 compression resistance属性

content hugging是让view抱紧,当view的宽度约束大于view的内在宽度,content hugging优先级设置的高,view不会拉伸

compression resistance是让view顶住,当view的宽度约束小于view的内在宽度,compression resistance优先级设置的高。view不会被压缩

UIScrollView约束

scrollView和他外部的item之间的约束,约束的是scrollView的frame

scrollView和他内部的item之间的edges和margins约束,约束的是scrollView的contentsize

scrollView和他内部的item之间的height, width,和centers约束,约束的是scrollView的frame

Visual Format Language

VFL:描述性语言。 H:[blueView]-8-[redView]

API: [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[blueView]-8-[redView]" options:NSLayoutFormatAlignAllTop metrics:nil views:NSDictionaryOfVariableBindings(blueView,redView)]];

缺点: 太太太太容易写错了

AutoLayout新特性

iOS 8:

新属性lastBaseline、firstBaseline、leftMargin、rightMargin、topMargin、bottomMargin、leadingMargin、trailingMargin、centerXMargin、centerYMargin

约束的激活的反激活:

@property (getter=isActive) BOOL active

[NSLayoutConstraint activateConstraints:constraintsArray]

[NSLayoutConstraint deactivateConstraints:constraintsArray]

iOS 9:

约束锚,NSLayoutAnchor,只需考虑约束,不用考虑加在哪个view上,类似Masonry

[imageView.trailingAnchor constraintEqualToAnchor:label.leadingAnchor constant:20]

UILayoutGuide:专门的辅助布局的控件,不会加到view上,但是可以“占位置”,省去了加一堆空白view辅助布局的烦恼

UILayoutGuide *space1 = [[UILayoutGuide alloc] init];

[self.view addLayoutGuide:space1];

UILayoutGuide *space2 = [[UILayoutGuide alloc] init];

[self.view addLayoutGuide:space2];

[space1.widthAnchor constraintEqualToAnchor:space2.widthAnchor].active = YES;

[self.saveButton.trailingAnchor constraintEqualToAnchor:space1.leadingAnchor].active = YES;

[self.cancelButton.leadingAnchor constraintEqualToAnchor:space1.trailingAnchor].active = YES;

[self.cancelButton.trailingAnchor constraintEqualToAnchor:space2.leadingAnchor].active = YES;

[self.clearButton.leadingAnchor constraintEqualToAnchor:space2.trailingAnchor].active = YES;

UIStackView:水平或垂直方向上一系列的view,以此排列,解决前一个view隐藏或删除,后面的view需要更新约束的尴尬

Masonry

github

https://github.com/SnapKit/Masonry

官方定义:

Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax. Masonry has its own layout DSL which provides a chainable way of describing your NSLayoutConstraints which results in layout code that is more concise and readable. Masonry supports iOS and Mac OS X

几个点:轻量级、基于AutoLayout、链式布局DSL、高可读性、支持iOS和OS X、有Swift版本SnapKithttps://github.com/SnapKit/SnapKit

NSLayoutConstraints的问题:

复杂,可读性太低

语法

添加约束:

[redView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.leading.equalTo(blueView.mas_trailing).multipliedBy(1).offset(8);

}];

更改约束:

mas_updateConstraints:注意只能改常数值

mas_remakeConstraints:删除之前与view相关的所有约束重新创建

删除约束: 需要记录约束

@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];

约束

约束属性:MASViewAttribute

约束关系:

.equalTo equivalent to NSLayoutRelationEqual

.lessThanOrEqualTo equivalent to NSLayoutRelationLessThanOrEqual

.greaterThanOrEqualTo equivalent to NSLayoutRelationGreaterThanOrEqual

优先级:

.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.leading.equalTo(self.view.mas_leading).multipliedBy(1).offset(0);

-----乘数是1可以省略,常数是0可以省略----->

make.leading.equalTo(self.view.mas_leading);

-----item1的属性和item2的属性相同,item2的属性可以省略----->

make.leading.equalTo(self.view);

-----item1直接添加在item2上,item2可以省略, 写@0----->

make.leading.equalTo(@(0));

-----equalTo每次常数值都要写@,好烦,可以用mas_equalTo----->

make.leading.mas_equalTo(0);

合并

[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {

            make.top.equalTo(self.view).offset(10);    

            make.left.equalTo(self.view).offset(10);

            make.bottom.equalTo(self.view).offset(-10);

            make.right.equalTo(self.view).offset(-10);

}];

-----item2和乘数和常数一致,可以合并在一行写----->

[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.top.left.equalTo(self.view).offset(10);

        make.bottom.right.equalTo(self.view).offset(-10);

}];

-----几个属性也可以合在一起----->

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.edges.equalTo(self.view).insets(padding);

}];

-----item1直接添加在item2上,equalTo和insets可合并----->

[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.edges.mas_equalTo(padding);

}];

合并合并:

height.and.width -->size

centerX.and.centerY --> center

例如:

make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))

make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))

合并合并合并:

item1和item1的属性一样,多个item2也可以合并在一行创建多个约束,传入数组即可

make.height.equalTo(@[view1.mas_height, view2.mas_height]);

make.height.equalTo(@[view1, view2]);

make.left.equalTo(@[view1, @100, view3.right]);

可读性:

make.top.left.equalTo(self.view).offset(10); --> make.top.and.left.equalTo(self.view).with.offset(10);

and和with并没有实际作用,只是单纯返回self,只为了可读性的考量

创建约束代码的位置

参考这篇博客:

http://reviewcode.cn/article.html?reviewId=14

View中:直接在init方法里创建.

ViewController中:直接在viewDidLoad()里创建.

何时更新:需要更新的代码如果比较少可以就在当时更新,比较多则放在updateConstraints() ,然后在合适的时候setNeedsUpdateConstraints() 批量更新

补充TableViewCell实践经验:创建时候在init中创建,在所有subview都加入了contentview之后,调用自定函数setupConstraints(),所有创建约束代码加载此处,可以避免约束创建的类没有添加到任何父类引发的崩溃。所有与model相关的约束更新放在updateConstraints()中,在bindWIthModel是调用setNeedsUpdateConstraints() 更新约束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,873评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,483评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,525评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,595评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,018评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,958评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,118评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,873评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,643评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,813评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,293评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,615评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,306评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,170评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,968评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,107评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,894评论 2 278