Osheep

时光不回头,当下最重要。

详解布局Masonry

1.概念

Masonry是一个轻量级的布局框架,拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性 而且同时支持 iOS 和 Mac OS X;是AutoLayout的一个第三方类库,用链式语法封装了冗长的AutoLayout代码,因此学习成本相对于官方提供的AutoLayout,以及VFL语言而言,低上很多很多…(用于纯代码布局);使用的时候导入头文件#import “Masonry.h”

2.支持的属性(如字面意思)

《详解布局Masonry》

屏幕快照 2016-12-30 下午4.22.01.png

备注:
1.简单的语法总结
with和and
基本没用过,方法的结果是返回对象本身,就是对其没有任何的操作.有人说就是为了代码的可读性,我道行太浅感觉有与没有差别不大.

  1. 用masonry时候,比如写距离上面控件10;若不标明是距离上面控件的下边界10,则默认是距离其上边界10,导致可能显示不出来,盖住。注意!!

3.三种设置约束的方法

mas_makeConstraints //第一次生成约束使用
给view添加约束,约束方式有几种,分别是边距,宽,高,左上右下距离,基准线。添加过
约束后可以有修正,修正有offset(位移)修正和multipliedBy(倍率)修正。
(语法有make.equalTo or make.greaterThan Or EqualTo or make.lessThanOrEqualTo + 倍数和位移修正。
使用 mas_makeConstraints方法的元素必须事先添加到父元素的中)

mas_updateConstraints //针对上面的情况 会更新在block中出现的约束 不会导致出现两个相同约束的情况
mas_remakeConstraints //重新生成约束,会将之前的所有约束先去掉(一般约束好一个控件,然后在特定情况下想重新布局,就用这个方法)

使用注意:在循环cell,如果有代码重复调用的地方,一定要使用mas_remakeConstraints,以此防止循环的时候生成相同的约束,影响性能,甚至,能使用make的地方基本都可以用remake进行代替,防止生成无谓的约束

mas_updateConstraints 针对上面的情况 会更新block中出现
的约束 不会导致出现两个相同的约束的情况

注意: 同一个对象 使用mas_updateConstraints 一定要保证block中要更新的元素是
其使用mas_makeConstraints 设置的约束,如下就是正确的 则不会出现约束冲突问题

[testView mas_updateConstraints:^(MASConstraintMaker *make) {
     make.bottom.equalTo(view1.mas_top).offset(-60);
     必须是 同一参照对象(都是以view1)同一参照属性(都是以view1的mas_top)
}];

但是下面的就不对了 就会出现约束冲突 在iOS 7 及其以下会出现由于约束冲突出现的崩溃

[testView mas_updateConstraints:^(MASConstraintMaker *make) { 
    make.bottom.equalTo(view2.mas_top).offset(-10);
    make.centerX.equalTo(view4.mas_centerX);
    原因1:不同一参照对象 (原来是view1 现在是view2)
    原因2 testView 在 mas_makeConstraints中没有设置 center 所以无法更新
}];
    解决办法:使用mas_remakeConstraints 清除原来的约束 重新设置约束;
}];

4.简单例子

例1:
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];//一定要先加入父控件,否则报错
[view mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];

**等价于**

[view mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.right.top.bottom.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];

**等价于**

[view mas_makeConstraints:^(MASConstraintMaker *make) {

make.left.equalTo(view.superview).offset(20);
make.top.equalTo(view.superview).offset(20);
make.right.equalTo(view.superview).offset(-20);
make.bottom.equalTo(view.superview).offset(-20);
}];
写法:
[imgV mas_makeConstraints:^(MASConstraintMaker *make) {

      make.size.mas_equalTo(CGSizeMake(17., 38.));
      make.left.equalTo(_startTimeLb);  
      make.top.equalTo(_startTimeLb.mas_bottom).with.offset(10.);
}];

make.height.greaterThanOrEqualTo(self.mas_bottom).offset(5);// 大于等于约束
mas_lessThanOrEqualTo:小于等于
写法:
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
           
      make.top.bottom.left.right.mas_equalTo(@(0));
}];

5.细节之处

1.关于mas_equalTo
Masonry表示相等有两种方法:equalTo和mas_equalTo
mas_equalTo其实就是多了一层处理的宏而已,因为equalTo并不支持基本数据类型;例如高度为300的约束中,可以这样写mak.height.equalTo(@300);或者这样写mak.height.mas_equalTo(300);
masequalTo 比equalTo多了类型转换操作,一般来说,大多数时候两个方法都是 通用的,但是对于数值元素使用mas_equalTo。对于对象或是多个属性的处理,使用equalTo。
mas_equalTo:这个方法会对参数进行封装( 可以跟数据和对象 )
equalTo:这个方法不会对参数进行封装( 后面括号里面必须是对象 )
现在的 mas_equalTo: > equalTo:

注意比例multipliedBy的使用:
make.width.equalTo(self.view.mas_width).multipliedBy(0.5);//设置宽度为self.view的一半,multipliedBy是倍数的意思,也就是,使宽度等于self.view宽度的0.5倍

6.Masonry布局时涉及动画

动画问题,和普通的方法实现差不多,重点只是修改约束后调用:
[view.superview layoutIfNeeded];而已
比如:

[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(400);
make.left.mas_equalTo(100);
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
[view.superview layoutIfNeeded];//如果其约束还没有生成的时候需要动画的话,就请先
强制刷新后才写动画,否则所有没生成的约束会直接跑动画
[UIView animateWithDuration:3 animations:^{
[view mas_updateConstraints:^(MASConstraintMaker *make) {make.left.mas_equalTo(200);
}];
[view.superview layoutIfNeeded];//强制绘制
}];

7. Masonry与Frame混用

需要调用方法layoutIfNeeded才会有效

看例子:

UIView *parent = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UIImageView *child = [UIView alloc] init];
[parent addSubview:child];
[child mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(20,20));
        make.top.left.mas_equalTo(50);
    }];
NSLog(@"%@",redView);

打印结果:
** <UIImageView: 0x7fb222605550; frame = (0 0; 0 0); layer = <CALayer: 0x7fb22260b3a0>>**

1.可以发现,虽然使用Masonry进行布局和约束,但是子视图child的frame仍然为(0, 0, 0 ,0)

2.原因:使用masonry的实质是调用了ios7以后的autolayout,如果要更新frame,需要调用layoutIfNeeded函数进行布局,然后所约束的控件才会按照约束条件,生成当前布局相应的frame和bounds。而调用layoutIfNeeded的目的是让系统调用layoutSubviews方法,我们也可以直接在这个方法里获取frame,因为这时候开始layout subviews,Masonry已经计算出了真实的frame

《详解布局Masonry》

屏幕快照 2017-10-26 下午2.20.01.png

8.相关链接

《详解布局Masonry》

屏幕快照 2016-12-30 下午4.43.16.png
《详解布局Masonry》

《详解布局Masonry》

屏幕快照 2016-12-30 下午4.39.22.png
《详解布局Masonry》

SDAutoLayout
https://github.com/gsdios/SDAutoLayout
MyLinearLayout
https://github.com/youngsoft/MyLinearLayout
Masonry介绍与使用实践(快速上手Autolayout)
UIScrollview与Autolayout的那点事
masonry:http://geek.csdn.net/news/detail/133417?ref=myread
备注

使用苹果原生方法时:
注意要将一属性关掉试图的属性self.view.autoresizingMask=NO;或者按钮的button.translatesAutoresizingMaskIntoConstraints=NO;

其他相关有关于自动布局的:

《详解布局Masonry》

QQ图片20160330100029.png
点赞