Masonry GitHub:https://github.com/SnapKit/Masonry

Masonry是一个轻量级的布局框架,拥有自己的描述语法,采用更优雅的链式语法封装自动布局,简洁明了并具有高可读性,而且同时支持 iOS 和 Mac OS X。Masonry是一个用代码写iOS或OS界面的库,可以代替Auto layout。

example :

 [view1 mas_makeConstraints:^(MASConstraintMaker *make) {    

     // 设置和superView 的边缘的缩进量
make.edges.equalTo(superview).with.insets(padding); }];

Masonry使用讲解

Masonry 支持的属性:

make 的属性:(MASConstraintMaker:)

 @interface MASConstraintMaker : NSObject

 /**
* The following properties return a new MASViewConstraint
* with the first item set to the makers associated view and the appropriate MASViewAttribute
*/
@property (nonatomic, strong, readonly) MASConstraint *left;
@property (nonatomic, strong, readonly) MASConstraint *top;
@property (nonatomic, strong, readonly) MASConstraint *right;
@property (nonatomic, strong, readonly) MASConstraint *bottom;
@property (nonatomic, strong, readonly) MASConstraint *leading;
@property (nonatomic, strong, readonly) MASConstraint *trailing;
@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *baseline;

其中leading与left trailing与right 在正常情况下是等价的 但是当一些布局是从右至左时, 则会对调 换句话说就是基本可以不理不用 用left和right就好了

需要添约束的View 的约束的属性:

 @interface MAS_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);

Masonry 提供了3个关于约束的方法:

 - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block; // mas_makeConstraints 只负责新增约束 Autolayout不能同时存在两条针对于同一对象的约束 否则会报错
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *make))block; // mas_updateConstraints 针对上面的情况 会更新在block中出现的约束 不会导致出现两个相同约束的情况
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block; // mas_remakeConstraints 则会清除之前的所有约束 仅保留最新的约束
三种函数善加利用 就可以应对各种情况了

mas_makeConstraints 是给view添加约束,约束有几种,分别是边距,宽,高,左上右下距离,基准线。

添加过约束后可以有修正,修正有offset(位移)修正和multipliedBy(倍率)修正。

语法一般是 make.equalTo or make.greaterThanOrEqualTo or make.lessThanOrEqualTo + 倍数和位移修正。

注意点1:

使用 mas_makeConstraints方法的元素必须事先添加到父元素的中,例如[self.view addSubview:view];

注意点2:

mas_equalTo 和 equalTo 区别:mas_equalTo 比equalTo多了类型转换操作,一般来说,大多数时候两个方法都是 通用的,但是对于数值元素使用mas_equalTo。对于对象或是多个属性的处理,使用equalTo。特别是多个属性时,必须使用equalTo.

举例 make.left.and.right.equalTo(self.view) ,  make.height.mas_equalTo(@20);

 #define mas_equalTo(...)                 equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...) greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...) lessThanOrEqualTo(MASBoxValue((__VA_ARGS__))) #define mas_offset(...) valueOffset(MASBoxValue((__VA_ARGS__)))

mas_equalTo 是一个宏,可以看到 mas_equalTo只是对其参数进行了一个BOX操作(装箱) MASBoxValue的定义具体可以看看源代码

所支持的类型 除了NSNumber支持的那些数值类型之外,就只支持CGPoint CGSize UIEdgeInsets

mas_greaterThanOrEqualTo 和 mas_lessThanOrEqualTo 这两个宏还有一个小技巧:

 #ifdef MAS_SHORTHAND_GLOBALS

 #define equalTo(...)                     mas_equalTo(__VA_ARGS__)
#define greaterThanOrEqualTo(...) mas_greaterThanOrEqualTo(__VA_ARGS__)
#define lessThanOrEqualTo(...) mas_lessThanOrEqualTo(__VA_ARGS__) #define offset(...) mas_offset(__VA_ARGS__) #endif

定义以下两个宏,在使用Masonry框架时就不需要加mas_前缀了
(定义宏一定要在引入Masonry.h文件之前).

 //define this constant if you want to use Masonry without the 'mas_' prefix
#define MAS_SHORTHAND
//define this constant if you want to enable auto-boxing for default syntax
#define MAS_SHORTHAND_GLOBALS // example #define MAS_SHORTHAND
#define MAS_SHORTHAND_GLOBALS
#import "Masonry.h"

注意点3: 注意到方法with和and,这连个方法其实没有做任何操作,方法只是返回对象本身,这这个方法的左右完全是为了方法写的时候的可读性 。

make.left.and.right.equalTo(self.view);和make.left.right.equalTo(self.view);是完全一样的,但是明显的加了and方法的语句可读性 更好点。

 #pragma mark - Semantic properties

 - (MASConstraint *)with {
return self;
} - (MASConstraint *)and {
return self;
}

小技巧:#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self;  快速的定义一个weakSelf ,用于block 里面,防止循环引用。

示例:

(1) 居中显示一个View :

     WS(weakSelf); // WS 是上面定义的一个宏
// 从此基本可以抛弃CGRectMake 了
UIView *sv = [UIView new];
sv.backgroundColor = [UIColor blackColor];
// 在做autoLayout 之前,一定要将view 添加到superView 上,否则会报错
[self.view addSubview:sv];
// mas_makeConstraints 就是Masonry 的autoLayout 添加函数,将所需的约束添加到block 中就行了
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
// 将sv 居中(很容易理解)
make.center.equalTo(weakSelf.view);
// 将size 设置为(400 ,400)
make.size.mas_equalTo(CGSizeMake(, ));
}];

(2)让一个View 略小于其superView(边距是10)

     // 让一个View 略小于其superView(边框为 10)
UIView *sv1 = [UIView new];
sv1.backgroundColor = [UIColor redColor];
[sv addSubview:sv1];
[sv1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(, , , ));
// 等价于
// make.top.equalTo(sv).with.offset(10);
// make.left.equalTo(sv).with.offset(10);
// make.bottom.equalTo(sv).with.offset(-10);
// make.right.equalTo(sv).with.offset(-10);
// 也等价于
// make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];

可以看到 edges 其实就是top,left,bottom,right的一个简化 分开写也可以 一句话更省事

那么为什么bottom和right里的offset是负数呢? 因为这里计算的是绝对的数值 计算的bottom需要小于sv的底部高度 所以要-10 同理用于right

(3)让两个高度为150 的View 垂直居中且等宽且等间隔排列 间隔是10 (自动计算其宽度)

     // 初级 让两个高度为150 的View 垂直居中且等宽且等间隔排列 间隔为10 (自动计算其宽度)
int padding1 = ;
UIView *sv2 = [UIView new];
sv2.backgroundColor = [UIColor yellowColor];
[sv addSubview:sv2];
UIView *sv3 = [UIView new];
sv3.backgroundColor = [UIColor yellowColor];
[sv addSubview:sv3]; [sv2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(sv.mas_centerY);
make.left.equalTo(sv.mas_left).with.offset(padding1);
make.right.equalTo(sv3.mas_left).with.offset(-padding1);
make.height.mas_equalTo(@);
make.width.equalTo(sv3);
}]; [sv3 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(sv.mas_centerY);
make.left.equalTo(sv2.mas_right).with.offset(padding1);
make.right.equalTo(sv.mas_right).with.offset(-padding1);
make.height.mas_equalTo(@);
make.width.equalTo(sv2);
}];

这里我们在两个子view之间互相设置的约束 可以看到他们的宽度在约束下自动的被计算出来了

(4)在UIScrollerView 顺序排列一些View 并自动计算contentSize

     // 中级 在UIScrollerView 顺序排列一些View 并自动计算contentSize
UIScrollView *scrollView = [UIScrollView new];
scrollView.backgroundColor = [UIColor whiteColor];
[sv addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(, , , )); // 约束UIScrollerView 的窗口视图的大小四边各缩进sv 5
}];
UIView *container = [UIView new]; // 起一个中间层的作用,能够自动计算UIScrollerView 的contentSize
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(scrollView); // left right top bottom
make.width.equalTo(scrollView);
}]; int count = ;
UIView *lastView = nil;
for (int i = ; i <= count; i++) {
UIView *subV = [UIView new];
[container addSubview:subV];
subV.backgroundColor = [UIColor colorWithHue:(arc4random() % / 256.0) saturation:(arc4random() % / 256.0) brightness:(arc4random() % / 256.0) alpha:]; // 设置背景颜色
[subV mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.and.right.equalTo(container);
make.height.mas_equalTo(@( * i)); // 每个子View 的高度不断增大一倍
if (lastView) {
make.top.mas_equalTo(lastView.mas_bottom); // lastView 做中间View 的传递,确定每个小View 的top
} else {
make.top.mas_equalTo(container.mas_top); // 第一个小View 的top 和container 相等
}
}];
lastView = subV;
} [container mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(lastView.mas_bottom); // container 的bottom 和最后一个小View 的bottom 相等
}];

(5)横向或者纵向等间隙的排列一组View

autoLayout并没有直接提供等间隙排列的方法(Masonry的官方demo中也没有对应的案例) 但是参考案例3 我们可以通过一个小技巧来实现这个目的 为此写一个Category

 #import "UIView+Masonry_LJC.h"
#import "Masonry.h" @implementation UIView (Masonry_LJC) - (void)distributeSpacingHorizontallyWith:(NSArray *)views {
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count + ]; for (int i = ; i < views.count + ; ++i) {
UIView *v = [UIView new];
[spaces addObject:v];
[self addSubview:v]; [v mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(v.mas_height); // 宽高相等
}];
} UIView *v0 = spaces[]; __weak __typeof (&*self) ws = self; [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(ws.mas_left);
make.centerY.equalTo(((UIView *)views[]).mas_centerY);
}]; UIView *lastSpace = v0;
for (int i = ; i < views.count; ++i) {
UIView *obj = views[i];
UIView *space = spaces[i + ]; [obj mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(lastSpace.mas_right);
}]; [space mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(obj.mas_right);
make.centerY.equalTo(obj.mas_centerY);
make.width.equalTo(v0);
}]; lastSpace = space;
} [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(ws.mas_right);
}];
} - (void)distributeSpacingVerticallyWith:(NSArray *)views {
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count + ]; for (int i = ; i < views.count + ; ++i) {
UIView *v = [UIView new];
[spaces addObject:v];
[self addSubview:v]; [v mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(v.mas_height);
}];
} UIView *v0 = spaces[]; __weak __typeof (&*self) ws = self; [v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(ws.mas_top);
make.centerX.equalTo(((UIView *)views[]).mas_centerX);
}]; UIView *lastSpace = v0;
for (int i = ; i < views.count; ++i) {
UIView *obj = views[i];
UIView *space = spaces[i + ]; [obj mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(lastSpace.mas_bottom);
}]; [space mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(obj.mas_bottom);
make.centerX.equalTo(obj.mas_centerX);
make.height.equalTo(v0);
}]; lastSpace = space;
} [lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(ws.mas_bottom);
}];
}
@end

测试:

     UIView *sv11 = [UIView new];
UIView *sv12 = [UIView new];
UIView *sv13 = [UIView new];
UIView *sv21 = [UIView new];
UIView *sv31 = [UIView new];
sv11.backgroundColor = [UIColor redColor];
sv12.backgroundColor = [UIColor redColor];
sv13.backgroundColor = [UIColor redColor];
sv21.backgroundColor = [UIColor redColor];
sv31.backgroundColor = [UIColor redColor];
[sv addSubview:sv11];
[sv addSubview:sv12];
[sv addSubview:sv13];
[sv addSubview:sv21];
[sv addSubview:sv31];
//给予不同的大小 测试效果
[sv11 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(@[sv12,sv13]);
make.centerX.equalTo(@[sv21,sv31]);
make.size.mas_equalTo(CGSizeMake(, ));
}];
[sv12 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(, ));
}];
[sv13 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(, ));
}];
[sv21 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(, ));
}];
[sv31 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(, ));
}];
[sv distributeSpacingHorizontallyWith:@[sv11,sv12,sv13]];
[sv distributeSpacingVerticallyWith:@[sv11,sv21,sv31]];

可以看下这个较复杂页面的约束,其中的桃红色的线条都是约束线:

本篇先到此,下篇做更深入的学习。

Coding源码学习第四部分(Masonry介绍与使用(一))的更多相关文章

  1. Coding源码学习第四部分(Masonry介绍与使用(三))

    接上篇继续进行Masonry 的学习. (12)tableViewCell 布局 #import "TableViewController.h" #import "Tes ...

  2. Coding源码学习第四部分(Masonry介绍与使用(二))

    接上篇,本篇继续对Masonry 进行学习,接上篇示例: (6)Masonry 布局实现iOS 计算器 - (void)exp4 { WS(weakSelf); // 申明区域,displayView ...

  3. mongo源码学习(四)服务入口点ServiceEntryPoint

    在上一篇博客mongo源码学习(三)请求接收传输层中,稍微分析了一下TransportLayer的作用,这篇来看下ServiceEntryPoint是怎么做的. 首先ServiceEntryPoint ...

  4. Java集合源码学习(四)HashMap分析

    ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...

  5. java源码学习(四)ArrayList

    ArrayList ​ ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ​ ArrayList不是线程安全的,只能用在单线程环境下, ...

  6. Java集合源码学习(四)HashMap

    一.数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据的存储,这两者有不同的应用场景,数组的特点是:寻址容易,插入和删除困难:链表的特点是:寻址困难,插入和删除容易:哈希表的实现结合了这两点, ...

  7. jquery 源码学习(四)构造jQuery对象-工具函数

    jQuery源码分析-03构造jQuery对象-工具函数,需要的朋友可以参考下.   作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原 ...

  8. mongo源码学习(四)invariant

    前言 在看MongoDB源码的时候,经常会看到这个玩意儿:invariant. invariant的字面意思是:不变式. 在emacs上跳转到函数定义要安装一个插件,ggtags,费了老大劲儿.这都可 ...

  9. TCMalloc源码学习(四)(小内存块释放)

    pagemap_和pagemap_cache_ PageHeap有两个map,pagemap_记录某一内存页对应哪一个span,显然可能多页对应一个span,pagemap_cache_记录某一内存页 ...

随机推荐

  1. 利用PhantomJS进行网页截屏,完美解决截取高度的问题

    关于PhantomJS PhantomJS 是一个基于WebKit的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS ...

  2. 让PictureBox支持URL显示图片

    [ToolboxItem(true)] public class PictureBoxURL : PictureBox { private string _url = ""; pu ...

  3. DP4J -- mnist

    标签(空格分隔): DeepLearning mnist mnist是一个数据集,其中包含很多手写数字的图片,每张图片都已经打上了label: Deep Learning 传统的机器学习神经网络由一层 ...

  4. 24.Redis2.8主从集群sentinel

    0.集群架构(此处只说两种;本文2种,避免sentinel成为单节点) 第一种: 第二种: 1.下载redis2.8.x版本,2.8.x都是稳定版 redis-2.8.24.tar.gz 2.解压,安 ...

  5. Ember.js 的视图层

    本指导会详尽阐述 Ember.js 视图层的细节.为想成为熟练 Ember 开发者准备,且包 含了对于入门 Ember 不必要的细节. Ember.js 有一套复杂的用于创建.管理并渲染连接到浏览器 ...

  6. 微软亚洲实验室一篇超过人类识别率的论文:Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification ImageNet Classification

    在该文章的两大创新点:一个是PReLU,一个是权值初始化的方法.下面我们分别一一来看. PReLU(paramter ReLU) 所谓的PRelu,即在 ReLU激活函数的基础上加入了一个参数,看一个 ...

  7. alter system switch logfile与alter system archive log current的区别

    以前知道 ALTER SYSTEM SWITCH LOGFILE对单实例数据库或RAC中的当前实例执行日志切换, ALTER SYSTEM ARCHIVE LOG CURRENT会对数据库中的所有实例 ...

  8. easyui combobox 左匹配模糊查询

    之前一直不知道,easyui 的combobox还有从左匹配查询显示数据的. 样式是这样的:(这是数据是已经存在下拉列表里的) 在这样操作的时候,遇到了一个问题.(其实也不算问题的). 就是操作人员在 ...

  9. .ashx datatable转excel

    using System;using System.Collections;using System.Collections.Generic;using System.Data;using Syste ...

  10. 后缀树(suffix tree)

    参考: 从前缀树谈到后缀树 后缀树 Suffix Tree-后缀树 字典树(trie树).后缀树 一.前缀树 简述:又名单词查找树,tries树,一种多路树形结构,常用来操作字符串(但不限于字符串), ...