前提

经过一点时间的使用,发现在网上很少有Masonry的教程,也仅仅有那么一两篇而已,在此我编写一下我最近一段时间使用的方法,供大家学习。

Masonry是AutoLayout的一个第三方类库,用链式语法封装了冗长的AutoLayout代码,因此学习成本相对于官方提供的AutoLayout,以及VFL语言而言,低上很多很多...

准备

在GitHub上 https://github.com/SnapKit/Masonry 下载配置第三方库,基本使用方法在Readme中也有说明,我就不赘述了,CocoaPods在我blog有相关的设置介绍 CocoaPods的安装使用

pod 'Masonry'

为了方便更新库来解决旧有bug,所以不写版本号 '~>x.x.x'

在pch文件中加入

#import "Masonry.h"

便可全局使用

基本用法

可以理解和Android五大布局中的相对布局一样,基本原理就是本控件相对于某个控件的位置,因此相对比较需要有一个参考控件

基本的计算公式为

控件左边 = 参考控件的右边 + 偏移值(5) (控件在参考控件的右边,距离其5px)

make.left.equalTo(view.superview.mas_right).offset(10);//不填则默认对应left,其他同理

支持的属性

@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;

方法

Masonry有三种设置约束的方法

mas_makeConstraints //第一次生成约束使用mas_updateConstraints    //更新其中的约束mas_remakeConstraints    //重新生成约束,会将之前的所有约束先去掉

使用注意:在循环cell,如果有代码重复调用的地方,一定要使用mas_remakeConstraints,以此防止循环的时候生成相同的约束,影响性能,甚至,能使用make的地方基本都可以用remake进行代替,防止生成无谓的约束

简单用法

初始化一个带边距的view

UIView *view = [[UIView alloc] init];view.backgroundColor = [UIColor redColor];[self.view addSubview:view];//一定要先加入父控件,否则报错[view mas_makeConstraints:^(MASConstraintMaker *make) {make.edges.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));}];

等价

[view mas_makeConstraints:^(MASConstraintMaker *make) {make.left.right.top.bottom.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));

left ,right等属性,如字面意思

等价

[view mas_makeConstraints:^(MASConstraintMaker *make) {make.left.equalTo(view.superview).offset(20);make.top.equalTo(view.superview).offset(20);make.right.equalTo(view.superview).offset(-20);make.bottom.equalTo(view.superview).offset(-20);}];

链式语法中,and 以及 with都是修饰性语句,不做任何事情,便于理解而已

make.bottom.and.top.equalTo(view.superview).with.offset(-20);

源码中

#pragma mark - Semantic properties- (MASConstraint *)with {return self;}- (MASConstraint *)and {return self;}

间隔View

子控件宽高为父控件的一半(multipliedBy)

[view mas_makeConstraints:^(MASConstraintMaker *make) {make.left.equalTo(view.superview);make.top.equalTo(view.superview).offset(20);make.width.height.equalTo(view.superview).multipliedBy(0.5);}];

这里写图片描述

大于小于

make.width.greaterThanOrEqualTo(@200);make.width.lessThanOrEqualTo(@400)

blcok中进行判断使用约束(在统一处理某些业务的时候)

[self.button mas_remakeConstraints:^(MASConstraintMaker *make) {make.size.equalTo(self.buttonSize);if (topLeft) {make.top.and.left.offset(10);} else {make.bottom.and.right.offset(-10);}}];死高度300 * 300

修改指定约束

MASConstraint *topConstraint;// 在生成约束的时候[view1 mas_makeConstraints:^(MASConstraintMaker *make) {topConstraint = make.top.equalTo(superview.mas_top);make.left.equalTo(superview.mas_left);}];...// 在之后进行对该约束 进行修改[topConstraint uninstall];

写死高度300 * 300

[view mas_makeConstraints:^(MASConstraintMaker *make) {make.center.equalTo(view.superview);make.width.height.equalTo(@300);}];

关于mas_equalTo使用

Masonry表示相等有两种方法,equalTo 和 mas_equalTo

mas_equalTo其实是多了一层处理的宏而已,因为equalTo并不支持基本数据类型

#define mas_equalTo(...)                equalTo(MASBoxValue((__VA_ARGS__)))

在高度为300的约束中,可以这样子写

mak.height.equalTo(@300);

也可以,使用mas_equalTo,一般情况下,我会全部使用mas_equalTo来处理基本数据类型的封装

mak.height.mas_equalTo(300);

并列排序-水平 或者 高度

经常会遇到很多需要等宽或者登高排序的需求,下面是我个人使用的一种方法,可以参考一下,但是需要说明的是,相对布局的各种用法很多,请思考便可以,同一种效果,N种写法

- (void)viewDidLoad {[super viewDidLoad];//都是相对于suerpview来设置位置的NSMutableArray *viewArray = [NSMutableArray array];NSArray *colorArray = @[[UIColor redColor],[UIColor blueColor],[UIColor orangeColor],[UIColor purpleColor]];for (int i = 0; i < colorArray.count ; i++) {UIView *view = [[UIView alloc] init];view.backgroundColor = colorArray[i];[self.view addSubview:view];[viewArray addObject:view];}[self sortVerticalWithViews:viewArray LeftMargin:50 Width:100 BackViewHeight:300];viewArray = [NSMutableArray array];for (int i = 0; i < colorArray.count ; i++) {UIView *view = [[UIView alloc] init];view.backgroundColor = colorArray[i];[self.view addSubview:view];[viewArray addObject:view];}[self sortHorizontalWithViews:viewArray TopMargin:320 TopView:self.view Height:100];}#pragma mark 将控件进行排序,更新其操作(水平)- (void)sortHorizontalWithViews:(NSArray *)views TopMargin:(NSInteger)topMargin TopView:(UIView *)topView Height:(NSInteger)viewH{__block UIView *leftView;[views enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {UIView *tempView = obj;[tempView mas_remakeConstraints:^(MASConstraintMaker *make) {if (idx == 0) {make.left.equalTo(tempView.superview);if ([topView isEqual:tempView.superview]) { //如果传入的是容器view 则上方无控件make.top.mas_equalTo(topView).offset(topMargin);} else {make.top.mas_equalTo(topView.mas_bottom).offset(topMargin);}make.width.mas_equalTo(tempView.superview.mas_width).multipliedBy((CGFloat)1 / views.count);make.height.mas_equalTo(viewH);} else {make.left.equalTo(leftView.mas_right);make.top.mas_equalTo(leftView);make.width.mas_equalTo(leftView);make.height.equalTo(leftView);}}];leftView = tempView;}];}#pragma mark 将控件进行排序,更新其操作(垂直)- (void)sortVerticalWithViews:(NSArray *)views LeftMargin:(NSInteger)leftMargin Width:(NSInteger)viewWidth BackViewHeight:(NSInteger)backViewHeight{__block UIView *topView;[views enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {UIView *tempView = obj;[tempView mas_remakeConstraints:^(MASConstraintMaker *make) {if (idx == 0) {make.left.equalTo(tempView.superview).offset(leftMargin);make.top.mas_equalTo(tempView.superview);make.width.mas_equalTo(viewWidth);make.height.mas_equalTo(backViewHeight / views.count);} else {make.left.equalTo(topView);make.top.mas_equalTo(topView.mas_bottom);make.width.mas_equalTo(topView);make.height.mas_equalTo(topView);}}];topView = tempView;}];}

这里写图片描述

动画问题

动画问题,和普通的方法实现差不多,重点只是修改约束后调用

[view.superview layoutIfNeeded];

而已

[view mas_makeConstraints:^(MASConstraintMaker *make) {make.top.mas_equalTo(400);make.left.mas_equalTo(100);make.size.mas_equalTo(CGSizeMake(100, 100));}];[view.superview layoutIfNeeded];//如果其约束还没有生成的时候需要动画的话,就请先强制刷新后才写动画,否则所有没生成的约束会直接跑动画[UIView animateWithDuration:3 animations:^{[view mas_updateConstraints:^(MASConstraintMaker *make) {make.left.mas_equalTo(200);}];[view.superview layoutIfNeeded];//强制绘制 }];

多个控件要相对于父控件居中

有时候会出现这种需求,这种情况下,最方便的做法就是,多个子控件放到一个容器里面,让容器自适应子控件宽度,然后容器相对于父控件居中

Paste_Image.png

Paste_Image.png
  • 因为我这里为了方便,就现在xib中用了个空白的superView去占位,后面好调整

大概步骤:

  1. 父控件 加入 容器
  2. 设置容器相对于父控件的位置
  3. 循环创建子控件
- (void)initCouponType:(PPProductDetailViewModel *)viewModel
{UIView *conView = [[UIView alloc] init];[self.couponTypeContainer addSubview:conView]; //父控件 加入 容器[conView makeConstraints:^(MASConstraintMaker *make) {make.height.top.centerX.equalTo(conView.superview);//width不设置,让其根据子控件宽度进行适配}];__block UIView *lastView = nil;//viewModel.couponTypeArray 为我的数据源,根据实际情况配置if (viewModel.couponTypeArray.count > 0) {[viewModel.couponTypeArray enumerateObjectsUsingBlock:^(GwCouponType *_Nonnull coupontype, NSUInteger idx, BOOL *_Nonnull stop) {//设置样式UIButton *newBtn = [[UIButton alloc] init];[newBtn setTitle:coupontype.couponTypename forState:UIControlStateNormal];//子控件加入到容器中[conView addSubview:newBtn];[newBtn makeConstraints:^(MASConstraintMaker *make) {//因为我这里用到的是button,在设置文字后,不设置宽度,系统就自适配宽度,label也同样,imageview设置图片后也一样,如果其他不能自适应,或者你需要自己设定的,就设置width就可以了//设置leftmake.left.equalTo(lastView ? lastView.mas_right : newBtn.superview).offset(3);//最后一个子控件设置右对齐容器if (idx == viewModel.couponTypeArray.count - 1) {make.right.equalTo(newBtn.superview).offset(3);}  //设置子控件相对于父控件Y轴对齐make.centerY.equalTo(newBtn.superview);// lastView让下一个控件知道自己左边的是什么,从而设置left属性  lastView = newBtn;}];}];}
}

Cell的高度计算

借鉴@星光社的戴铭 的方法 [AutoLayout框架Masonry使用心得]
(http://www.jianshu.com/p/24e4ff56bfea)
也可以参考forkingdog的FDTemplateLayoutCell

  • iOS8 以上
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 80; //减少第一次计算量,iOS7后支持- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {return UITableViewAutomaticDimension;//返回即可
}
  • iOS7
//在model中添加属性缓存高度
@interface DataModel : NSObject
@property (copy, nonatomic) NSString *text;
@property (assign, nonatomic) CGFloat cellHeight; //缓存高度
@end- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {static CustomCell *cell;//只初始化一次cellstatic dispatch_once_t onceToken;dispatch_once(&onceToken, ^{cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomCell class])];});DataModel *model = self.dataArray[(NSUInteger) indexPath.row];if (model.cellHeight <= 0) {[cell makeupData:model];//使用systemLayoutSizeFittingSize获取高度model.cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;}return model.cellHeight;
}
  • 以上参考(这里面还有其他很多case,各位看看~)
    有趣的Autolayout示例-Masonry实现

遇到的问题

AutoLayout是在iOS7 之后才刚刚推出的一种新的方法,因为在iOS7系统上并不能算得上十分完善,经常有一些bug,然而在iOS8中相对好的处理了

  • 最明显的问题就是scorllView的contentSize问题

  • 系统的约束并不是在设置完成之后里面进行绘图的,而是在最后ViewDidApper()这个函数前一些时间才完成绘图,而且每次绘制(比如,往scorllView上添加新的子控件,即增加了新的约束)后,scorllView的contentOffset和contentSize都会初始化为0,因此每次都需要重新设置(如果你在绘制前已经设置了contentSize的话),或者你可以使用tableView来代替scorllView

- (void)viewDidAppear:(BOOL)animated{[super viewDidAppear:animated];_scorllView.contentSize = CGSizeMake(200, 200);}
  • 如果你需要在约束设置完成后立马得到frame的数值的话,调用
[view.superview layoutIfNeeded];

之后会强制性更新约束,这句话之后便可以得到frame,在iOS8中只需要在这加入设置contentSize便可以实现正常的scrollView滚动,而iOS7中则不可以,请注意。

而且如果出现什么疑难杂症的话,基本都是AutoLayout在iOS的不适用,所以搜索问题的话,各位直接搜索Autolayout 关键字便可,不必搜索Masonry关键字的问题(反正也搜不到什么答案...)

  • contentView的冲突
  • 如果遇到和contentView的冲突,基本原因是因为cell的content view有一个系统的约束(高度),而masonry是不会去管理非自己产生的约束,因此在使用label imageview等情况下,增加以下属性设置,确保优先级以防止冲突
[_contentLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
文/邦Ben(简书作者)
原文链接:http://www.jianshu.com/p/2b57ece2b3b8
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

Masonry的使用,动画,出现问题解决等相关推荐

  1. cocoscreator网页小游戏iphonex/xr等异面屏手机播放动画闪烁问题解决

    背景 往app产品内嵌入一款H5小游戏,ios手机型号iphonexr.cocoscreator版本v2.4.2. 问题描述 小游戏,在播放animation动画的时候,整个游戏界面闪烁.在公司iph ...

  2. AutoLayout 浅析动画

    1.AutoLayout相关的几个易混淆的方法 setNeedsLayout layoutIfNeeded layoutSubViews setNeedsUpdateConstraints updat ...

  3. Masonry自动布局详解五:比例(multipliedBy)

    Masonry自动布局详解五:比例(multipliedBy) 标签: iosmasonryautolayout自动布局约束 2015-11-30 16:30 1816人阅读 评论(0) 收藏 举报 ...

  4. [京东实践干货]手把手教你实现「京喜工厂」的CSS动画效果

    0 契机与背景 今年Q1(2020年第一季度)参与了京喜事业部「京喜工厂」业务的前端开发.用户可以通过「京喜工厂」参与口罩.抽纸.大米等商品的"在线生产",既能趣味造物,又能免费领 ...

  5. 5.jquery事件与动画

    一.事件(重要) 1.jquery绑定事件 jQuery对象.bind("事件名",可选参数,事件处理函数) 注意: 1.第二个参数为可选参数,作为event.data属性值传递给 ...

  6. 开源一个天气APP Build with React Native

    About Github 断断续续花了几天的时间,利用网上开放的小米天气接口,基于React native 写了一个天气APP.App store 在审核中.设计能力有限,天气动画只加了两个,AE导出 ...

  7. RecyclerView notifyItem闪屏问题

    原文链接 http://blog.csdn.net/chenliguan/article/details/52809758 http://www.jianshu.com/p/654dac931667 ...

  8. 【iOS】仿写iOS计算器总结

    iOS计算器 思路解构 MVC Masonry布局 设计时的问题解决 代码 View Model 计算表达式: 思路解构 要学会写计算器,必须要学会用栈来实现四则运算,同时要实现复杂运算的前提,就增加 ...

  9. ios canvas ,movable-area爬坑之旅

    小程序canvas爬坑之旅 canvas ios 报错canvasToTempFilePath:fail no image? <canvas type="2d" id=&qu ...

最新文章

  1. python PIL(pillow) Image模块的基础功能
  2. C# does not contain a constructor that takes no parameter
  3. 《工业控制网络安全技术与实践》一一第3章 工业控制网络安全威胁
  4. python ctypes struct_Python之ctypes
  5. npm -S -D -g i 有什么区别
  6. laravel sql多个orWhere条件时数据查询错误
  7. virtualenv之python虚拟环境
  8. 有关python_30个有关Python的小技巧
  9. 【Flutter】基础组件【07】Appbar
  10. 计算机中汉字字库分为哪两种,常用的汉字字库有GB2312字库和GBK字库两种。 (转)...
  11. 手把手带你可视化分析 NBA 季后赛
  12. win2003服务器360修复漏洞打不开网页,360浏览器打不开网页,教您怎样解决360浏览器打不开网页...
  13. 不用找了,大厂在用的分库分表方案,都在这了
  14. 不要说话 -- 陈奕迅/小柯
  15. 微信Wifi物联架构---机智云/云智易如何接入微信硬件平台
  16. coso2dx-lua 电脑模拟器 , 不重启游戏 直接让修改过的 lua 代码 生效
  17. 现在还有人看武侠小说吗?
  18. win11专业版降为家庭版
  19. 单片机叮咚c语言,单片机试验19“叮咚”门铃
  20. 北邮通信土著--非技术路线备忘录 (摘自北邮人论坛)

热门文章

  1. Moodle平台使用问题集锦
  2. 使用Navicat 连接oracle “ORA-03135: Connection Lost Contact”
  3. 跟我一起写 Makefile -- 陈皓
  4. swf用html怎么写,swfobject.js html中写入一个swf文件
  5. 豆瓣FM duilib版
  6. Lightly:新一代的 Go IDE
  7. 联想卡在logo界面_联想电脑卡在载入界面如何修复 联想电脑卡在logo界面
  8. 麻烦攻克食材串味难题!保姆级除味妙招请查收
  9. windows下面常用的渗透测试命令(安全工具)
  10. python如何逐行读取文件_Python逐行读取文件中内容的简单方法