手把手教你Masonry的理解
看什么看!点我呀! 全栈程序员,免费入门到精通!
作者丨未知
http://www.cocoachina.com/ios/20160912/17564.html
我们先来看看是如何开始使用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就有点混淆。。。
- (id)initWithView:(MAS_VIEW *)view {
self = [super init]; if (!self) return nil;
self.view = view;
self.constraints = NSMutableArray.new;
return self;
}
比如可以更改为上面的形式...
这段代码的理解就是初始化了一个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_rem
这几个方法分别是添加约束,更新约束以及注销约束,前面已经将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。
推荐↓↓↓
长
按
关
注
?【16个技术公众号】都在这里!
涵盖:程序员大咖、源码共读、程序员共读、数据结构与算法、黑客技术和网络安全、大数据科技、编程前端、Java、Python、Web编程开发、Android、iOS开发、Linux、数据库研发、幽默程序员等。
万水千山总是情,点个 “ 好看” 行不行
手把手教你Masonry的理解相关推荐
- 手把手教你做自然语言理解智能对话的微信小程序【核心源码】
闲聊-智能对话:微信小程序详解 重要提醒:第三方私人语音接口已关闭,现已更新至官方语音接口,如有问题请联系博主 重要更新!!!! 现在"智能聊"小程序支持语音输入了!!!!! 完整 ...
- Node.js 高级篇(六):手把手教你使用和理解 Multer 实现文件上传,包懂 O(∩_∩)O~
文章目录 前端 界面 代码 服务端 启动服务 文件信息 Multer 中间件 Multer(options) .single(fieldname) .array(fieldname[, maxCoun ...
- 手把手教你看懂并理解Arduino PID控制库——调参改变
2019独角兽企业重金招聘Python工程师标准>>> 引子 本文将分析<手把手教你看懂并理解Arduino PID控制库>中第三个问题:PID控制参数突变对系统的影响. ...
- 手把手教你理解卷积神经网络
摘要: 卷积神经网络是一种识别和理解图像的神经网络.本文将从不同的层次来介绍卷积神经网络. 手把手教你理解卷积神经网络(一) 本文将继续为你介绍关于卷积神经网络的知识.为了保持文章的简洁性和全面性我将 ...
- 还没理解微前端?手把手教你实现一个迷你版
大厂技术 高级前端 Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 最近看了几个微前端框架的源码(single-spa[1].qiankun[2].micro- ...
- 2021年大数据Hive(三):手把手教你如何吃透Hive数据库和表操作(学会秒变数仓大佬)
全网最详细的Hive文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 系列历史文章 前言 Hive数据库和表操作 一.数据库操作 1.创建数据库 2.创建 ...
- Linux环境搭建 | 手把手教你安装Linux虚拟机
2019独角兽企业重金招聘Python工程师标准>>> 前言 作为一名Linux工程师,不管是运维.应用.驱动方向,在工作中肯定会需要Linux环境.想要获得Linux环境,一个办法 ...
- 手把手教你安装Linux虚拟机
点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 01 前言 作为一名Linux工程师,不管是运维.应用.驱动方向,在工作中肯定会需要Linux ...
- skywalking原理_Skywalking系列博客6手把手教你编写 Skywalking 插件
点击上方 IT牧场 ,选择 置顶或者星标技术干货每日送达! 前置知识 在正式进入编写环节之前,建议先花一点时间了解下javaagent(这是JDK 5引入的一个玩意儿,最好了解下其工作原理):另外,S ...
最新文章
- c++引用另一个类的方法_VlookUp函数使用方法,一张表引用另一张表的数据。
- spi时序图怎么分析,怎么看懂spi时序图
- linux实时备份,51CTO博客-专业IT技术博客创作平台-技术成就梦想
- 现在做Android开发有前途吗?附面试题答案
- 以后出去找工作,只能说自己是产品策划了
- 网络安全系列之三十九 在Linux中配置访问控制列表ACL
- E 定向 牛客练习赛25
- linux fopen文件失败,fopen自动创建文件失败(文件路径检查创建)
- nfine框架 上传文件_NFine快速开发框架
- 【寄明月】MMD动作镜头下载-附赠扇子和使用方法
- 获取上个月第一天和最后一天
- vue实现li列表的新增删除和修改
- 定时计数程序c语言,MCS-51系列单片机C语言编程定时/计数器程序模板
- 培养创造性思维的20个技巧!
- python AMQP 客户端连接
- Oracle入门(学习整理)
- 百度智能云虚拟主机搭建ThinkPHP5.0项目
- wifi密码本 字典(免费二)
- loadrunner入门教程(6) --新建脚本
- 吉西他滨纳米载药细胞膜囊泡|红细胞囊泡包载的纳米药物(齐岳试剂)
热门文章
- 远程桌面提示CredSSP加密数据库修正
- Elsevier期刊模板2(官方要求+文章结构)
- json字符串,JSONObject对象,JavaBean对象互转。
- 剑指offer T48 不含重复字符的最长子串
- 全新跨平台版本.NET敏捷开发框架-RDIFramework.NET5.0震撼发布
- 技术人员的职业规划(方向)
- 投影仪幕布增益_钱别瞎乱花 家用投影幕布应该怎么选?
- 爷青结!微软凌晨宣布“再见”!
- 十七.C++网络安全学院之CE扫描和基础
- 养生主——离散数学篇