Masonry
是一个轻量级的布局框架,它拥有本身的描述语法(采用更优雅的链式语法封装)来自动布局,具备很好可读性且同时支持iOS和Max OS X
等。
总之,对于侧重写代码的coder,请你慢慢忘记Frame
,喜欢Masonry
吧ios
如果你对于自动布局很熟练的话,再接触这个第三方
Masonry
很容易上手的,对UI界面显示的控件的约束本质都是相同的,如今呢,我通常都是喜欢在控制器里导入#import "Masonry.h"
以前再添加两个宏,来提升App的开发效率。git
//1. 对于约束参数能够省去"mas_" #define MAS_SHORTHAND
//2. 对于默认的约束参数自动装箱 #define MAS_SHORTHAND_GLOBALS
即:须要咱们导入的框架与宏以下github
//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或子类的实例
。数组
约束的属性app
在此我就列举几个可能不太熟悉的吧框架
@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
不须要设置控件的translatesAutoresizingMaskIntoConstraints
属性为NO
;
防止block
中的循环引用,使用弱引用(这是错误观点),在这里block
是局部的引用,block
内部引用self
不会形成循环引用的
__weak typeof (self) weakSelf = self
;(不必的写法)less
当约束冲突发生的时候,咱们能够设置view的key来定位是哪一个view
redView.mas_key = @"redView";
greenView.mas_key = @"greenView";
blueView.mas_key = @"blueView";
如果以为这样一个个设置比较繁琐,怎么办呢,Masonry则提供了批量设置的宏MASAttachKeys
MASAttachKeys(redView,greenView,blueView); //一句代码便可所有设置dom
约束iconView
距离各个边距为30ide
[iconView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(30, 30, 30, 30)); }];
#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个函数
/** * 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); }];
水平方向等间隔.png
水平方向控件宽度固定等间隔.png
对于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]; }
多行label约束.png
原理同自动布局同样 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); }]; }