Coding源码学习第四部分(Masonry介绍与使用(一))
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介绍与使用(一))的更多相关文章
- Coding源码学习第四部分(Masonry介绍与使用(三))
接上篇继续进行Masonry 的学习. (12)tableViewCell 布局 #import "TableViewController.h" #import "Tes ...
- Coding源码学习第四部分(Masonry介绍与使用(二))
接上篇,本篇继续对Masonry 进行学习,接上篇示例: (6)Masonry 布局实现iOS 计算器 - (void)exp4 { WS(weakSelf); // 申明区域,displayView ...
- mongo源码学习(四)服务入口点ServiceEntryPoint
在上一篇博客mongo源码学习(三)请求接收传输层中,稍微分析了一下TransportLayer的作用,这篇来看下ServiceEntryPoint是怎么做的. 首先ServiceEntryPoint ...
- Java集合源码学习(四)HashMap分析
ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...
- java源码学习(四)ArrayList
ArrayList ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下, ...
- Java集合源码学习(四)HashMap
一.数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据的存储,这两者有不同的应用场景,数组的特点是:寻址容易,插入和删除困难:链表的特点是:寻址困难,插入和删除容易:哈希表的实现结合了这两点, ...
- jquery 源码学习(四)构造jQuery对象-工具函数
jQuery源码分析-03构造jQuery对象-工具函数,需要的朋友可以参考下. 作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原 ...
- mongo源码学习(四)invariant
前言 在看MongoDB源码的时候,经常会看到这个玩意儿:invariant. invariant的字面意思是:不变式. 在emacs上跳转到函数定义要安装一个插件,ggtags,费了老大劲儿.这都可 ...
- TCMalloc源码学习(四)(小内存块释放)
pagemap_和pagemap_cache_ PageHeap有两个map,pagemap_记录某一内存页对应哪一个span,显然可能多页对应一个span,pagemap_cache_记录某一内存页 ...
随机推荐
- UVA 11520 填充正方形
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- JAVA 冒泡算法
每种语言都有冒泡JAVA实现如下: public static void main(String args[]){ System.out.println("Start"); int ...
- iOS NSURLConnection POST异步请求封装,支持转码GBK,HTTPS等
.h文件 #import <Foundation/Foundation.h> //成功的回调 typedef void(^successBlock)(id responseObj); // ...
- KEEPALIVED
keepalived 一.原理: 功能:能够自动实现将用户访问的ip转移的方法,故障重启,故障,恢复切换,故障报警 模型:Master/Backup 使用场景:节点少,没有共享存储等等.他只能有一个主 ...
- 无法启动调试。未安装Silverlight Developer运行时。最新运行时可以从以下地址下载: http://go.microsoft.com/fwlink/?LinkId=146060.
无法启动调试.未安装Silverlight Developer运行时.最新运行时可以从以下地址下载: http://go.microsoft.com/fwlink/?LinkId=146060. 解决 ...
- ReportDesigner中实现保存,保存所有,注册ICommandHandler方式实现
示例: https://www.devexpress.com/Support/Center/Example/Details/E4354
- Markdown学习和插件介绍
markdown能干啥 亲们github上的项目首页的 内容+样式,都是项目中README.md文件控制的.将md风格的代码,转化成html. 而且markdown语法非常简单,5-10分钟即可学会! ...
- system_call中断处理过程
张雨梅 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10000 1.给menuos添加命令 改 ...
- easyx与VS2015
7.10 之前在文件头将__acrt_iob_func重定义&__iob_func,在格子涂色的程序中解决了问题:然而在俄罗斯方块的程序中出现了更多的问题,好像是FILE在其他外部依赖项cor ...
- unity自带寻路Navmesh入门教程(二)
上一节简单介绍了NavMesh寻路的基本用法,这次来介绍一下稍微复杂一点点的高低落差以及跳跃的做法,首先来看看这次的目标: 由于博客相册上传GIF有限制,所以我把整个过程切开了2部分上传,第一部分 ...