手把手教你Masonry的理解

我们先来看看是如何开始使用Masonry的,一般我们使用这个布局框架的时候,都会调用以下代码。。。。。

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

make.left.mas_equalTo(50);

make.right.mas_equalTo(-50);

make.top.mas_equalTo(50);

make.bottom.mas_equalTo(-50);

}];

我们来分析下这段代码,UIView类型的使用了mas_makeConstraints这个方法,这个是写在分类里面的,有一个block参数,我们看一下里面的实现代码:

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

block(constraintMaker);    return [constraintMaker install];

}

首先设置translatesAutoresizingMaskIntoConstraints属性为NO

第二行初始化了一个MASConstraintMaker类,那这个类里面做了什么操作呢,好吧,本着刨根问底的精神我们继续往下看

- (id)initWithView:(MAS_VIEW *)view {

self = [super init];    if (!self) return nil;

self.view = view;

self.constraints = NSMutableArray.new;

return self;

}

将当前的view赋给maker类,然后初始化constraints,这是一个约束数组。

我们仔细看block(constraintMaker);这一行代码。。。

神马意思呢?

首先这个block是(void(^)(MASConstraintMaker *))类型的一个参数,我们其实可以更改为其它名称,感觉用block就有点混淆。。。

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))constraintMakerblock {

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

constraintMakerblock(constraintMaker);    return [constraintMaker install];

}

比如可以更改为上面的形式...

这段代码的理解就是初始化了一个constraintMaker类,然后设置它的constraint属性,最后加载安装(install)

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

make.left.mas_equalTo(50);

make.right.mas_equalTo(-50);

make.top.mas_equalTo(50);

make.bottom.mas_equalTo(-50);

}];

注意:这种写法很容易理解为这是一个block,但其实只是在执行一个函数,后面一大块只不过是函数的一个参数而已,只不过它的参数是一个函数。

它等价与下面的一种写法:

self.view1.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self.view1];

constraintMaker.left.mas_equalTo(50);

constraintMaker.right.mas_equalTo(-50);

constraintMaker.top.mas_equalTo(50);

constraintMaker.bottom.mas_equalTo(-50);

[constraintMaker install];

那这样写的话就不是很方便了,那么有什么办法吗???

我们把它封装成一个函数???好的,封装成一个函数我们要做几件事情

-(void)addMakeConstraints

{

//初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

//设置它的属性

//  .........

//加载

[constraintMaker install];

}

那么第二步该怎么做呢?

传参数???但是参数有很多呀??怎么办??

比如我设置一个字典,里面用key,value来表示(left:50,right:-50,top:50,bottom:-50)好像也可以,但总觉的不是很方便

-(void)addMakeConstraints:(NSMutableDictionary *)dictionary

{

//初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

//设置它的属性

//  .........

constraintMaker.left.mas_equalTo([dictionary[@"left"] intValue]);

constraintMaker.right.mas_equalTo([dictionary[@"right"] intValue]);

constraintMaker.top.mas_equalTo([dictionary[@"top"] intValue]);

constraintMaker.bottom.mas_equalTo([dictionary[@"bottom"] intValue]);

//加载

[constraintMaker install];

}

NSMutableDictionary *constraint=[[NSMutableDictionary alloc]init];

[constraint setObject:@"50" forKey:@"left"];

[constraint setObject:@"-50" forKey:@"right"];

[constraint setObject:@"50" forKey:@"top"];

[constraint setObject:@"-50" forKey:@"bottom"];

[self.view1 addMakeConstraints:constraint];

貌似也可以实现的额,那有没有什么更好地办法呢?我们看下第一种写法:

-(void)addMakeConstraints

{

//初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

//设置它的属性

//  .........

//加载

[constraintMaker install];

}

其实我们中间就是缺了一段代码:那可以使用delegate吗

-(void)addMakeConstraints

{

//初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

[self.del addConstraint:constraintMaker];

//加载

[constraintMaker install];

}

-(void)addConstraint:(MASConstraintMaker *)maker

{

maker.left.mas_equalTo(50);

maker.right.mas_equalTo(-50);

maker.top.mas_equalTo(50);

maker.bottom.mas_equalTo(-50);

}

既然可以用代理实现,那么block肯定也是可以的

好的,我们改装成block版本

-(void)addMakeConstraints

{

//初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

self.makerBlock(constraintMaker);

//加载

[constraintMaker install];

}

[self.view1 addMakeConstraints];

self.view1.makerBlock=^(MASConstraintMaker *maker){

maker.left.mas_equalTo(50);

maker.right.mas_equalTo(-50);

maker.top.mas_equalTo(50);

maker.bottom.mas_equalTo(-50);

};

在这里,我们是作为一个属性来使用block的,那么我们还可以直接用参数作为block来实现的。

也就是说把这段代码封装成一个block参数

-(void)addMakeConstraints:(void(^)(MASConstraintMaker *maker))maker

{    //初始化MASConstraintMaker

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

maker(constraintMaker);

//加载    [constraintMaker install];

}

[self.view1 addMakeConstraints:^(MASConstraintMaker *make)

{

make.left.mas_equalTo(50);

make.right.mas_equalTo(-50);

make.top.mas_equalTo(50);

make.bottom.mas_equalTo(-50);

}];

至此,这段代码已经分析完毕,哈哈,总结就一句话:初始化MASConstraintMaker类,然后设置属性,最后加载,不同的就是将设置属性作为代码块调到实现的类里面来了而已。

好的 我们看下View+MASAdditions类

/**

*    following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute */@property (nonatomic, strong, readonly) MASViewAttribute *mas_left;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_top;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_right;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottom;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_leading;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailing;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_width;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_height;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;

@property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)@property (nonatomic, strong, readonly) MASViewAttribute *mas_firstBaseline;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_lastBaseline;#endif#if TARGET_OS_IPHONE || TARGET_OS_TV@property (nonatomic, strong, readonly) MASViewAttribute *mas_leftMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_rightMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_topMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_leadingMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailingMargin;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerXWithinMargins;

@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerYWithinMargins;

这一段是对MASViewAttribute的声明,看它的名字就知道这一段是对NSLayoutAttribute的封装,我们知道NSLayoutAttribute只是一些属性的枚举,那么封装有什么意义呢?

好吧,我们看下这段代码:

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

make.top.mas_equalTo(self.view1.mas_bottom).offset(10);

}];

有个self.view1.mas_bottom,我们知道要设置这个属性的话,要使用原生的方法:

NSLayoutConstraint *constaint=[NSLayoutConstraint constraintWithItem:self

attribute:att

relatedBy:NSLayoutRelationEqual

toItem:attribute.view

attribute:attribute.attribute

multiplier:1.0

constant:space];

在这里有个toItem,那要设置toItem就必须知道当前是哪个view,如果只有NSLayoutAttribute属性的话,这段代码中得toItem是设置不了的。

所以MASViewAttribute便添加了view这个属性,方便这个地方的设置MAS---View---Attribute,可以这么理解,哈哈!

/**

*  Creates a MASConstraintMaker with the callee view.

*  Any constraints defined are added to the view or the appropriate superview once the block has finished executing

*

*  @param block scope within which you can build up the constraints which you wish to apply to the view.

*

*  @return Array of created MASConstraints */- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))constraintMakerblock;/**

*  Creates a MASConstraintMaker with the callee view.

*  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.

*  If an existing constraint exists then it will be updated instead.

*

*  @param block scope within which you can build up the constraints which you wish to apply to the view.

*

*  @return Array of created/updated MASConstraints */- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block;/**

*  Creates a MASConstraintMaker with the callee view.

*  Any constraints defined are added to the view or the appropriate superview once the block has finished executing.

*  All constraints previously installed for the view will be removed.

*

*  @param block scope within which you can build up the constraints which you wish to apply to the view.

*

*  @return Array of created/updated MASConstraints */- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block;

这几个方法分别是添加约束,更新约束以及注销约束,前面已经将mas_makeConstraints这个方法讲的很详细了,后面两个方法类似。

只不过多了两个变量来控制:constraintMaker.updateExisting = YES;constraintMaker.removeExisting = YES;

好的,我们接着向下看:

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))constraintMakerblock {

self.translatesAutoresizingMaskIntoConstraints = NO;

MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];

constraintMakerblock(constraintMaker);    return [constraintMaker install];

}

第一步:将maker的view设置为当前view

第二步:设置属性

第三步:加载

我们看下第二步:

make.left.mas_equalTo(50);

make.right.mas_equalTo(-50);

make.top.mas_equalTo(50);

make.bottom.mas_equalTo(-50);

第二步用的链式结构,如果不懂得话可以看看我之前的文章。

make.left返回的MASConstraint类型

- (MASConstraint * (^)(id attr))mas_equalTo;

- (MASConstraint * (^)(id attr))mas_greaterThanOrEqualTo;

- (MASConstraint * (^)(id attr))mas_lessThanOrEqualTo;

- (MASConstraint * (^)(id))mas_equalTo {

return ^id(id attribute) {

return self.equalToWithRelation(attribute, NSLayoutRelationEqual);

};

}

然后执行mas_equalTo的方法:

它的返回值是:MASConstraint * (^)(id) 一个block。

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

推荐阅读更多精彩内容