代码适配Masonry使用的详细介绍
Masonry简介
Masonry
是一个轻量级的布局框架,它拥有自己的描述语法(采用更优雅的链式语法封装)来自动布局,具有很好可读性且同时支持iOS和Max OS X
等。
总之,对于侧重写代码的coder,请你慢慢忘记Frame
,喜欢Masonry
吧
使用前的准备
若是你对于自动布局很熟练的话,再接触这个第三方
Masonry
很容易上手的,对UI界面显示的控件的约束本质都是相同的,现在呢,我一般都是喜欢在控制器里导入#import "Masonry.h"
之前再添加两个宏,来提高App的开发效率。
//1. 对于约束参数可以省去"mas_"
#define MAS_SHORTHAND
//2. 对于默认的约束参数自动装箱
#define MAS_SHORTHAND_GLOBALS
即:需要我们导入的框架与宏如下
//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
#import "Masonry.h" //宏必须添加在头文件前面
添加约束前提:被约束的必须有父控件,其中约束项都必须是
UIView或子类的实例
。
约束的属性
在此我就列举几个可能不太熟悉的吧
@property (nonatomic, strong, readonly) MASConstraint *leading; //首部
@property (nonatomic, strong, readonly) MASConstraint *trailing; //尾部
@property (nonatomic, strong, readonly) MASConstraint *baseline; //文本基线
约束的三种方法
/**
//这个方法只会添加新的约束
[blueView mas_makeConstraints:^(MASConstraintMaker *make) {
}];
// 这个方法会将以前的所有约束删掉,添加新的约束
[blueView mas_remakeConstraints:^(MASConstraintMaker *make) {
}];
// 这个方法将会覆盖以前的某些特定的约束
[blueView mas_updateConstraints:^(MASConstraintMaker *make) {
}];
*/
`
常见约束的各种类型
/**
1.尺寸:width、height、size
2.边界:left、leading、right、trailing、top、bottom
3.中心点:center、centerX、centerY
4.边界:edges
5.偏移量:offset、insets、sizeOffset、centerOffset
6.priority()约束优先级(0~1000),multipler乘因数, dividedBy除因数
*/
Masonry约束易忽略的技术点
使用
Masonry
不需要设置控件的translatesAutoresizingMaskIntoConstraints
属性为NO
;
防止block
中的循环引用,使用弱引用(这是错误观点),在这里block
是局部的引用,block
内部引用self
不会造成循环引用的__weak typeof (self) weakSelf = self
;(没必要的写法)
Masonry约束控件出现冲突的问题
当约束冲突发生的时候,我们可以设置view的key来定位是哪个view
redView.mas_key = @"redView";
greenView.mas_key = @"greenView";
blueView.mas_key = @"blueView";
若是觉得这样一个个设置比较繁琐,怎么办呢,Masonry则提供了批量设置的宏MASAttachKeys
MASAttachKeys(redView,greenView,blueView); //一句代码即可全部设置
约束iconView
距离各个边距为30
[iconView makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(30, 30, 30, 30));
}];
equalTo 和 mas_equalTo的区别
#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
只是对其参数进行了一个BOX
(装箱) 操作,目前支持的类型:数值类型(NSNumber)、 点(CGPoint)、大小(CGSize)、边距(UIEdgeInsets)
,而equalTo:
这个方法不会对参数进行包装。
//常见约束的写法 这里太简单了 ,就不备注了
[iconView makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-30);
make.top.equalTo(self.view).offset(30);
make.height.width.equalTo(100); //== make.size.equalTo(100);
//make.size.mas_equalTo(self.view).multipliedBy(0.5);
//make.top.greaterThanOrEqualTo(self.view).offset(padding);
}];
[redView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(10); //with 增强可读性
make.left.equalTo(greenView.mas_right).and.offset(10); //and 增强可读性
make.bottom.equalTo(blueView.mas_top).offset(-10);
make.right.equalTo(superview.mas_right).offset(-10);
make.width.equalTo(greenView.mas_width);
make.height.equalTo(@[greenView, blueView]); //约束参数相同可以通过数组
}];
更新约束的问题
例如:控制器有个按钮,若是点击按钮,则按钮本身的大小、位置会随机改变
- 监听按钮点击
[self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
处理事件
(void) didClickBtn:(UIButton *)button {
self.btnSize = CGSizeMake(self.btnSize.width * 1.3, self.btnSize.height * 1.3); //设置一个属性(btnSize)保存其大小的变化 //1.告知需要更新约束,但不会立刻开始,系统然后调用updateConstraints
[self setNeedsUpdateConstraints]; //2.告知立刻更新约束,系统立即调用updateConstraints
[self updateConstraintsIfNeeded]; //3.这里动画当然可以取消,具体看项目的需求
//系统block内引用不会导致循环引用,block结束就会释放引用对象
[UIView animateWithDuration:0.4 animations:^{
[self layoutIfNeeded]; //告知页面立刻刷新,系统立即调用updateConstraints
}];
}苹果官方建议:添加/更新约束在这个方法
(updateConstraints)
内
// this is Apple's recommended place for adding/updating constraints
- (void)updateConstraints {
//更新约束
[self.btn updateConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.width.equalTo(@(self.buttonSize.width)).priorityLow();
make.height.equalTo(@(self.buttonSize.height)).priorityLow();
make.width.lessThanOrEqualTo(self);
make.height.lessThanOrEqualTo(self);
}];
//according to apple super should be called at end of method
//最后必须调用父类的更新约束
[super updateConstraints];
}
- 设置
requiresConstraintBasedLayout
为YES
+ (BOOL)requiresConstraintBasedLayout{
return YES ; //重写这个方法 若视图基于自动布局的
}
重置约束的问题
对于控件的重新约束,则之前的约束都是无效的,步骤都更新约束一样的,只是在updateConstraints
方法内的约束方法改为了remakeConstraints
,直接贴代码吧(仍以按钮为例,其他原理都是相同的)
//首先监听按钮
[self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
//处理事件
- (void) didClickBtn :(UIButton *)button{
(...) //触发条件
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
/**
* 动画展示变化 - 这句代码可有可无,参考项目具体的需求
* [UIView animateWithDuration:0.4 animations:^{
* [self layoutIfNeeded];
* }];
*/
}
//重置约束
- (void)updateConstraints {
[self.btn remakeConstraints:^(MASConstraintMaker *make) {
.....
}];
[super updateConstraints];
}
+ (BOOL)requiresConstraintBasedLayout{
return YES ; //重写这个方法 若视图基于自动布局的
}
多个(2个以上)控件的等间隔排序显示
首先介绍2个函数
/**
* axisType 轴线方向
* fixedSpacing 间隔大小
* fixedItemLength 每个控件的固定长度/宽度
* leadSpacing 头部间隔
* tailSpacing 尾部间隔
*
*/
//1. 等间隔排列 - 多个控件间隔固定,控件长度/宽度变化
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing
tailSpacing:(CGFloat)tailSpacing;
//2. 等间隔排列 - 多个固定大小固定,间隔空隙变化
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
withFixedItemLength:(CGFloat)fixedItemLength
leadSpacing:(CGFloat)leadSpacing
tailSpacing:(CGFloat)tailSpacing;
//首先添加5个视图
NSMutableArray *array = [NSMutableArray new];
for (int i = 0; i < 5; i ++) {
UIView *view = [UIView new];
view.backgroundColor = [UIColor greenColor];
[self addSubview:view];
[array addObject:view]; //保存添加的控件
}
//水平方向控件间隔固定等间隔
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:15 leadSpacing:10 tailSpacing:10];
[array makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(50);
make.height.equalTo(70);
}];
//水平方向宽度固定等间隔
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:70 leadSpacing:10 tailSpacing:10];
[array makeConstraints:^(MASConstraintMaker *make) { //数组额你不必须都是view
make.top.equalTo(50);
make.height.equalTo(70);
}];


多行label的约束问题
对于UILabel
文字内容多的问题,个人觉得Masonry
约束设置的非常简单优雅,在此非常感谢Masonry
的作者@Robert Payne
//创建label
self.label = [UILabel new];
self.label.numberOfLines = 0;
self.label.lineBreakMode = NSLineBreakByTruncatingTail;
self.label.text = @"有的人,没事时喜欢在朋友圈里到处点赞,东评论一句西评论一句,比谁都有存在感。等你有事找他了,他就立刻变得很忙,让你再也找不着。真正的朋友,平常很少联系。可一旦你遇上了难处,他会立刻回复你的消息,第一时间站出来帮你。所谓的存在感,不是你有没有出现,而是你的出现有没有价值。存在感,不是刷出来的,也不是说出来的。有存在感,未必是要个性锋芒毕露、甚至锋利扎人。翩翩君子,温润如玉,真正有存在感的人,反而不会刻意去强调他的存在感。他的出现,永远都恰到好处。我所欣赏的存在感,不是长袖善舞巧言令色,而是对他人的真心关照;不是锋芒毕露计较胜负,而是让人相处得舒服;不是时时刻刻聒噪不休,而是关键时刻能挺身而出。别总急着出风头,希望你能有恰到好处的存在感。";
[self addSubview: self.label];
[self.label makeConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(10);
make.right.equalTo(-10);
}];
//添加约束
- (void)layoutSubviews {
//1. 执行 [super layoutSubviews];
[super layoutSubviews];
//2. 设置preferredMaxLayoutWidth: 多行label约束的完美解决
self.label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
//3. 设置preferredLayoutWidth后,需要再次执行 [super layoutSubviews];
//其实在实际中这步不写,也不会出错,官方解释是说设置preferredLayoutWidth后需要重新计算并布局界面,所以这步最好执行
[super layoutSubviews];
}

UIScrollView的问题
原理同自动布局一样 UIScrollView上添加UIView
UIView上添加需要显示的控件 UIScrollView滚动高度取决于显示控件的总高度
对子控件做好约束,可达到控制UIView的大小
//创建滚动视图
UIScrollView *scrollView = [UIScrollView new];
self.scrollView = scrollView;
scrollView.backgroundColor = [UIColor grayColor];
[self addSubview:scrollView];
[self.scrollView makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
[self setUpContentView]; //添加内容视图
- (void)setUpContentView {
//约束UIScrollView上contentView
UIView *contentView = [UIView new];
[self.scrollView addSubview:contentView];
[contentView makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.scrollView);
make.width.equalTo(self.scrollView); //此处必填 - 关键点
}];
//添加控件到contentView,约束原理与自动布局相同
UIView *lastView;
CGFloat height = 30;
for (int i = 0; i <1 5; i ++) {
UIView *view = UIView.new;
view.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 256.0 green:arc4random() % 255 / 256.0 blue:arc4random() % 255 / 256.0 alpha:1.0];
[contentView addSubview:view];
[view makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(lastView ? lastView.bottom : @0);
make.left.equalTo(0);
make.width.equalTo(contentView.width);
make.height.equalTo(height);
}];
height += 30;
lastView = view;
}
[contentView makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(lastView.bottom);
}];
}

Masonry
源码GitHub
地址下载:Masonry
代码适配Masonry使用的详细介绍的更多相关文章
- iOS纯代码适配masonry中mas_的问题
//equalto 和 mas_equalto 是有区别的.但是我们不打算去了解,可以通过添加以下代码来统一. //注意!! 宏定义必须要放在 import 引入头文件之前! //define thi ...
- 【代码编译器】vscode 配置详细介绍
前言:运行环境.net6.0 C#10 安装.NET Core SDK和运行 官网下载地址:https://www.microsoft.com/net/download/core 安装.Net 4.7 ...
- Xilinx Vivado的使用详细介绍(1):创建工程、编写代码、行为仿真
Xilinx Vivado的使用详细介绍(1):创建工程.编写代码.行为仿真 Author:zhangxianhe 新建工程 打开Vivado软件,直接在欢迎界面点击Create New Projec ...
- autoLyout纯代码适配
前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时 ...
- react-native热更新之CodePush详细介绍及使用方法
react-native热更新之CodePush详细介绍及使用方法 2018年03月04日 17:03:21 clf_programing 阅读数:7979 标签: react native热更新co ...
- 安卓app开发-05-Android xml布局详细介绍
安卓app开发-05-Android xml布局详细介绍 虽然说有 墨刀,墨客 这些图形化开发工具来做 Android 的界面设计,但是我们还是离不开要去学习做安卓原生app,学习 xml 布局还是必 ...
- 详细介绍如何自研一款"博客搬家"功能
前言 现在的技术博客(社区)越来越多,比如:imooc.spring4All.csdn.cnblogs或者iteye等,有很多朋友可能在这些网站上都发表过博文,当有一天我们想自己搞一个博客网站时就会发 ...
- [No0000A7]批处理经常用到的变量及批处理>NUL详细介绍
绝对路径是指调用绝对的程序位置的路径,例如: start C:\Windows\test.exe 相对路径是文件改变路径以后还会按照变量的路径所在位置去调用,例如: start %WINDIR%\te ...
- php CGI、Fastcgi、PHP-FPM的详细介绍与之间的关系
以下PHP CGI.Fastcgi.PHP-FPM的一些信息归纳和汇总----->详细介绍与之间的关系 一:CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的 web ...
随机推荐
- POJ 2323 贪心
题意: 思路: 贪 贪 贪 如果当前的c>之前的c+s 那么之前的合适 一直贪下去就好了 //By SiriusRen #include <cstdio> #include < ...
- ssh框架的总结
一.spring:是基础,可以管理对象,也可以通过关键对象管理另一个框架.但是首先应该明确spring并不是只能应用于web方面,而是可以应用在一般的java项目中.只是如果在web环境下使用需要在w ...
- AIX查看HBA卡的WWN号
1,获得AIX主机连接的光纤设备: # lsdev -Cc adapter -S a | grep fcs fcs0 Available 09-08 FC Ad ...
- 2017国家集训队作业[arc076d/f][Exhausted?]
2017国家集训队作业[arc076d/f][Exhausted?] 题意: 有\(N\)个人,\(M\)把椅子,给出\(...L_i.R_i\)表示第\(i\)个人可以选择编号为\(1\sim ...
- 从excel 获取内容 模块:xlrd
import xlrd # 获取表的对象 excel = xlrd.open_workbook(‘a.excel’) # 获取所有excel里的所有表 table_list = excel.sheet ...
- 【开卷故意】JAVA正則表達式模版
专业既然是机器学习.那工作肯定也是继续和数据打交道,那么问题来了,非常多时候推荐算法和数据挖掘算法都是现成可用的,平台初建,重点还在数据过滤和抽取.如何高效的抽取数据? 利用往常算法比赛中经常使用的字 ...
- Spring中的AOP注解方式和XML方式
应掌握内容:1. AOP的全名2. AOP的实现原理[静态代理和动态代理]3. 注解方式的配置4. 通知类型 A. 每种通知的特点和使用方式 B. 获取各种数据,方便日后操作5. 执行表 ...
- Windows 下 Sublime Text 默认打开方式问题解决办法
Sublime Text 2 是很受ACMer喜爱的文本编辑器 但是绿色版删除后无法设置为默认打开方式...而且网上也没有给出明确的解决办法 注册表的解决办法: 删除 HKEY_CURRENT_USE ...
- vue踩坑记- Cannot find module 'wrappy'
找不到模块"包装" 当你维护别人的项目代码的时候,在自己这里电脑上运行,打开一个项目cnpm run dev的时候,报错如下 Cannot find module 'wrappy' ...
- mysql-5.7.19-winx64服务无法启动解决方案
解压mysql压缩包时没有data文件夹,不要手动创建,在cmd下直接运行命令: mysqld –initialize-insecure,data文件夹会自动生成,注意单词千万不要拼错,不要写成–in ...