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

时间:2021-09-15 00:22:58

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(, ));
}];

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

(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));
}];

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

可以看到 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);
}];

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

这里我们在两个子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 相等
}];

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

(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介绍与使用(一))

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

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

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

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

  1. Coding源码学习第四部分&lpar;Masonry介绍与使用&lpar;三&rpar;&rpar;

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

  2. Coding源码学习第四部分&lpar;Masonry介绍与使用&lpar;二&rpar;&rpar;

    接上篇,本篇继续对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. javafx之HTTP协议交互

    javafx端要获取获取如下信息: 服务器端获取的数据: javafx客户端发送的数据以及获取的数据: 工程目录: package Httputil; import IPsite.IPaddress; ...

  2. 强大的矩阵奇异值分解&lpar;SVD&rpar;及其应用

    版权声明: 本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com, 本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系wheeleast@gm ...

  3. ios 修正waring:Method override for the designated initializer of the superclass &&num;39&semi;-init&&num;39&semi; not found

    swift引入后,为了使oc和swift更相近,对oc的初始化方法也进行了修正,具体说明,见下面的链接,这个waring的最简单的修正方法是,到相应类的头文件中,去掉在自定义初始化方法后面的 NS_D ...

  4. Memcached监听多个端口&lowbar;同一台Windows机器中启动多个Memcached服务

    下载Memcached服务器 假设你解压在"C:\Program Files\memcached\memcached.exe" 那么可以如下创建多个服务监听不同的端口啦 监听第一个 ...

  5. Hibernate,Session清理缓存时间点

    当应用程序调用org.hibernate.Transaction的commit()的时候,commit()方法先清理缓存,然后再向数据库提交事务. 当应用程序显示调用Session.flush()方法 ...

  6. hdu 5451 Best Solver 矩阵循环群&plus;矩阵快速幂

    http://acm.hdu.edu.cn/showproblem.php?pid=5451 题意:给定x    求解 思路: 由斐波那契数列的两种表示方法, 之后可以转化为 线性表示 F[n] = ...

  7. ios开发——实用技术篇&amp&semi;XML协议详解

    XML的数据协议组成 名词 说明 md5 message-digest algorithm 5 http hypertext transfer protocol xml extensible mark ...

  8. git代码提交流程

    1.进入我的项目文件夹所在目录: 2.git status 查看我修改过的文件: 3.git add -A 将修改的文件全部添加, git add 文件名  只添加指定的文件名: 4.git comm ...

  9. toupper函数及一些小程序

    toupper 原型:extern int toupper(int c); 用法:#include <ctype.h> 功能:将字符c转换为大写英文字母 说明:如果c为小写英文字母,则返回 ...

  10. win10 store 无法连接网络

    当你试过所有的解决攻略 都无效时,那么使用这个教程 关闭以下的蓝色框里的