為什么要做這個(gè)筆記
masonry 可以說(shuō)是當(dāng)前 iOS開(kāi)發(fā)中最流行的 Autolayout框架,其極大的簡(jiǎn)化了蘋(píng)果原生提供的AutoLayout語(yǔ)法。目前很多大廠也是用的這個(gè)自動(dòng)布局框架,我司也在用。在此之前我一只在用另一個(gè)叫 SDAutolayout的自動(dòng)布局庫(kù),所以 masonry 是個(gè)初學(xué)者,如果寫(xiě)得不好的地方還希望大佬指點(diǎn)江山。經(jīng)過(guò)前段時(shí)間的開(kāi)發(fā)項(xiàng)目,對(duì)masonry框架有了大致的認(rèn)識(shí),用法上面基本能解決所有布局問(wèn)題。
masonry 基礎(chǔ)約束用法
- 首先先提及一下,view 在執(zhí)行 masonry 布局之前必須添加到父視圖上
- 約束的寫(xiě)法有好幾種,我先拿三種來(lái)舉例
- 第一種。mas_equalTo()方法傳入一個(gè)依賴的約束邊,如下面示例中“self.view.mas_left”,后面跟著 mas_offset()方法可以傳入一個(gè)值,這個(gè)值是相對(duì)于所依賴約束的偏移量。mas_offset()也可以不寫(xiě),默認(rèn)偏移0。
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view.mas_left).mas_offset(50);//左邊相對(duì)于 self.view 的 left 偏移50個(gè)單位
make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);//右邊相對(duì)于 self.view 的 right 偏移-50個(gè)單位
make.top.mas_equalTo(self.view.mas_top).mas_offset(100);//頂邊相對(duì)于 self.view 的 top 偏移100個(gè)單位
make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);//底邊相對(duì)于 self.view 的 bottom 偏移-100個(gè)單位
}];
- 第二種。mas_equalTo()只需要傳入相對(duì)的約束的視圖,不需要指定約束邊,默認(rèn)取前面第一個(gè)需要添加約束的邊
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view).mas_offset(50);//等價(jià)于 make.left.mas_equalTo(self.view.mas_left).mas_offset(50);
make.right.mas_equalTo(self.view).mas_offset(-50);//等價(jià)于 make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);
make.top.mas_equalTo(self.view).mas_offset(100);//等價(jià)于 make.top.mas_equalTo(self.view.mas_top).mas_offset(100);
make.bottom.mas_equalTo(self.view).mas_offset(-100);//等價(jià)于 make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);
}];
- 第三種。mas_equalTo() 傳入一個(gè)值,這個(gè)值就是相對(duì)于依賴父視圖對(duì)應(yīng)相同約束的偏移量
UIView *demoView = [[UIView alloc] init];
demoView.backgroundColor = UIColor.greenColor;
[self.view addSubview:demoView];
[demoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(50);//等價(jià)于 make.left.mas_equalTo(demoView.superview.mas_left).mas_offset(50);
make.right.mas_equalTo(-50);//等價(jià)于 make.right.mas_equalTo(demoView.superview.mas_right).mas_offset(-50);
make.top.mas_equalTo(100);//等價(jià)于 make.top.mas_equalTo(demoView.superview.mas_top).mas_offset(100);
make.bottom.mas_equalTo(-100);//等價(jià)于 make.bottom.mas_equalTo(demoView.superview.mas_bottom).mas_offset(-100);
}];
三種寫(xiě)法結(jié)果是一致的,效果圖如下

看你個(gè)人喜歡用哪一種,我個(gè)人比較懶,喜歡用第三種,所以都是以第三種寫(xiě)法作為描述
居左上
YYLabel *leftTopLabel = [[YYLabel alloc] init];
leftTopLabel.backgroundColor = UIColor.redColor;
leftTopLabel.text = @"居左上";
leftTopLabel.textColor = UIColor.whiteColor;
leftTopLabel.textAlignment = NSTextAlignmentCenter;
leftTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:leftTopLabel];
[leftTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(0);
make.top.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
效果如下

居左下
YYLabel *leftBottomLabel = [[YYLabel alloc] init];
leftBottomLabel.backgroundColor = UIColor.redColor;
leftBottomLabel.text = @"居左下";
leftBottomLabel.textColor = UIColor.whiteColor;
leftBottomLabel.textAlignment = NSTextAlignmentCenter;
leftBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:leftBottomLabel];
[leftBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(0);
make.bottom.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];
效果如下

居右上
YYLabel *rightTopLabel = [[YYLabel alloc] init];
rightTopLabel.backgroundColor = UIColor.redColor;
rightTopLabel.text = @"居右上";
rightTopLabel.textColor = UIColor.whiteColor;
rightTopLabel.textAlignment = NSTextAlignmentCenter;
rightTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:rightTopLabel];
[rightTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_offset(0);
make.top.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];

居右下
YYLabel *rightBottomLabel = [[YYLabel alloc] init];
rightBottomLabel.backgroundColor = UIColor.redColor;
rightBottomLabel.text = @"居右下";
rightBottomLabel.textColor = UIColor.whiteColor;
rightBottomLabel.textAlignment = NSTextAlignmentCenter;
rightBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:rightBottomLabel];
[rightBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_offset(0);
make.bottom.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];

垂直水平居中
YYLabel *centerLabel = [[YYLabel alloc] init];
centerLabel.backgroundColor = UIColor.redColor;
centerLabel.text = @"居中";
centerLabel.textColor = UIColor.whiteColor;
centerLabel.textAlignment = NSTextAlignmentCenter;
centerLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[demoView addSubview:centerLabel];
[centerLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];

子控件來(lái)?yè)纹鸶缚丶母叨?/h2>
平常在開(kāi)發(fā)過(guò)程中,經(jīng)常有這種情況就是父控件高度是根據(jù)子控件內(nèi)容動(dòng)態(tài)變化,用masonry來(lái)實(shí)現(xiàn)這個(gè)功能相當(dāng)簡(jiǎn)單,這里有幾個(gè)知識(shí)點(diǎn);
- 約束類對(duì)象
MASConstraint,通過(guò)點(diǎn)進(jìn)mas_makeConstraints:方法的實(shí)現(xiàn),源碼如下
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
咋們暫且先不管 MASConstraintMaker 類,找到最后一句constraintMaker對(duì)象調(diào)用了 install 方法并返回;進(jìn)入到這個(gè)install的實(shí)現(xiàn),源碼實(shí)現(xiàn)如下
- (NSArray *)install {
if (self.removeExisting) {
NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
for (MASConstraint *constraint in installedConstraints) {
[constraint uninstall];
}
}
NSArray *constraints = self.constraints.copy;
for (MASConstraint *constraint in constraints) {
constraint.updateExisting = self.updateExisting;
[constraint install];
}
[self.constraints removeAllObjects];
return constraints;
}
其中最上面的那個(gè)判斷條件在調(diào)用mas_remakeConstraints:方法時(shí)會(huì)被執(zhí)行到,咋們也不看。咋們看下面這一段,其實(shí) self.constraints 數(shù)組 就是在mas_makeConstraints:的 block 塊中添加的所有約束對(duì)象,接下來(lái) self.constraints 執(zhí)行 copy 并遍歷執(zhí)行 constraint.updateExisting = self.updateExisting;和[constraint install];,for 循環(huán)體中的第一句是標(biāo)記更新約束還是新添加的約束,第二句是對(duì)約束裝載,如果把第二句給注視掉,則添加的所有約束都不會(huì)被添加上,各位可以試一試;在方法的最后 返回了constraints數(shù)組,這個(gè)數(shù)組里面裝的是 MASConstraint 類對(duì)象,再回到上面 mas_makeConstraints:方法中,最后的 return [constraintMaker install];實(shí)際上就是返回另一個(gè)約束對(duì)象的數(shù)組,沒(méi)問(wèn)題把。咋們?cè)谡{(diào)用mas_makeConstraints:方法時(shí)可以用一個(gè)數(shù)組來(lái)接收,沒(méi)毛病。。看代碼
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
咋們?cè)趤?lái)看兩個(gè)方法,mas_offset()/mas_equalTo(),這兩個(gè)方法其實(shí)就是一個(gè)宏,點(diǎn)進(jìn)去看源碼如此
#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__)))
#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
mas_equalTo 對(duì)應(yīng) equalTo 方法,mas_offset 對(duì)應(yīng) valueOffset 方法,這兩個(gè)其實(shí)就是 Block 執(zhí)行體,返回是調(diào)用者對(duì)象(連式編程的標(biāo)志性語(yǔ)法),這個(gè)對(duì)象也就是MASConstraint類對(duì)象。繼續(xù)下去。篇幅有點(diǎn)長(zhǎng),這個(gè)知識(shí)點(diǎn)就到這里把。
- 約束的卸載
uninstall,使用MASConstraint對(duì)象調(diào)用這個(gè)uninstall,就會(huì)把約束從對(duì)應(yīng)的view上卸載掉;如下代碼
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
//卸載約束
for (MASConstraint *constraint in constraints) {
[constraint uninstall];
}
等價(jià)于
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
__block MASConstraint *top = nil;
__block MASConstraint *left = nil;
__block MASConstraint *right = nil;
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
left = make.left.mas_offset(20);
right = make.right.mas_offset(-20);
top = make.top.mas_offset(100);
}];
//卸載約束
[left uninstall];
[right uninstall];
[top uninstall];
- 約束的裝載
install,使用MASConstraint對(duì)象調(diào)用這個(gè)install,就會(huì)把約束裝載到對(duì)應(yīng)的view上;如下代碼
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(20);
make.right.mas_offset(-20);
make.top.mas_offset(100);
}];
//裝載約束
//for (MASConstraint *constraint in constraints) {
// [constraint install];
//}
等價(jià)于
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
__block MASConstraint *top = nil;
__block MASConstraint *left = nil;
__block MASConstraint *right = nil;
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
left = make.left.mas_offset(20);
right = make.right.mas_offset(-20);
top = make.top.mas_offset(100);
}];
//裝載約束
//[left install];
//[right install];
//[top install];
預(yù)備知識(shí)講完了,開(kāi)始完成功能
- 首先定義三個(gè)全局屬性必須得用到的
@interface Demo2ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end
- 寫(xiě)一個(gè)
createDemo方法來(lái)實(shí)現(xiàn)案列, 并調(diào)用這個(gè)方法
- (void)viewDidLoad {
[super viewDidLoad];
[self createDemo];
}
- (void)createDemo {
//...案例代碼在這里實(shí)現(xiàn)
}
- 創(chuàng)建
superView,不給 superView 高度,高度通過(guò)他的子視圖給撐起來(lái)
- (void)createDemo {
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[self.view addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
make.top.mas_equalTo(100);
}];
}
- 創(chuàng)建一個(gè)添加按鈕,沒(méi)點(diǎn)擊一下添加一個(gè)view在這個(gè)添加按鈕下面
- (void)createDemo {
/*。。。。*/
UIButton *button = [[UIButton alloc] init];
[button setTitle:@"增加" forState:UIControlStateNormal];
button.backgroundColor = UIColor.redColor;
[button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
[superView addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(10);
make.top.mas_equalTo(10);
make.right.mas_equalTo(-10);
self.bottom = make.bottom.mas_equalTo(-10);//記錄下這個(gè)約束對(duì)象
make.height.equalTo(@(100));
}];
}
- 在
superView的下方添加一個(gè)blueView,這個(gè)視圖blueView的頂部始終距離superView的底部10
- (void)createDemo {
/*。。。。*/
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = UIColor.blueColor;
[self.view addSubview:blueView];
[blueView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
make.top.mas_equalTo(superView.mas_bottom).mas_offset(10);
make.height.mas_equalTo(@(100));
}];
}
- 把
superView賦值給self.superView,把button賦值給self.bottomView
- (void)createDemo {
/*。。。。*/
self.superView = superView;
self.bottomView = button;
}
運(yùn)行效果圖如下

- 實(shí)現(xiàn)添加方法
action:,就能實(shí)現(xiàn)動(dòng)態(tài)撐大父視圖了
static int num = 0;
- (void)action:(UIButton *)button {
//卸載舊的底部約束
[self.bottom uninstall];
num += 1;
YYLabel *view = [[YYLabel alloc] init];
view.backgroundColor = UIColor.redColor;
view.text = [NSString stringWithFormat:@"控件%d", num];
view.textAlignment = NSTextAlignmentCenter;
view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[self.superView addSubview:view];
//給新 view 添加約束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.superView.mas_left).offset(10);
make.top.mas_equalTo(self.bottomView.mas_bottom).offset(10);
make.right.mas_equalTo(self.superView.mas_right).offset(-10);
//添加新的底部約束
self.bottom = make.bottom.mas_equalTo(self.superView.mas_bottom).offset(-10);
make.height.equalTo(@(100));
}];
self.bottomView = view;
}
效果圖如下

masonry 在 UIScrollView 中的運(yùn)用
masonry + UIScrollView 通過(guò)兩個(gè)示例,一個(gè)是水平方向,另一個(gè)垂直方向,這也是平常開(kāi)發(fā)中會(huì)遇到的。在使用masonry對(duì)UIScrollView設(shè)置約束后,contentSize屬性就不管用了,而需要通過(guò)masonry 的規(guī)則在scrollView中添加一個(gè) contentView,其它的子視圖全部添加到 contentView 上,讓contentView來(lái)?yè)纹餟IScrollview的 contentSize。
水平方向滑動(dòng)
- 第一步創(chuàng)建一個(gè)Scrollview
// 水平方向滾動(dòng)視圖
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = UIColor.greenColor;
scrollView.pagingEnabled = YES;
[self.view addSubview:scrollView];
//設(shè)置 Scrollview 的約束
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.view).offset(100);
make.left.mas_equalTo(10);
make.right.mas_equalTo(-10);
make.bottom.mas_equalTo(-100);
}];
- 創(chuàng)建一個(gè) contentView 放到Scrollview上,并設(shè)置約束
// 設(shè)置scrollView的子視圖,即過(guò)渡視圖contentSize
UIView *contentView = [[UIView alloc] init];
[scrollView addSubview:contentView];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(scrollView);
make.height.mas_equalTo(scrollView);
}];
- 動(dòng)態(tài)添加子視圖到 contentView 上
UIView *previousView = nil;
for (int i = 0; i < 10; i++) {
YYLabel *label = [[YYLabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.numberOfLines = 2;
label.backgroundColor = UIColor.redColor;
label.text = [NSString stringWithFormat:@"水平方向\n第 %d 個(gè)視圖", (i + 1)];
// 添加到父視圖,并設(shè)置過(guò)渡視圖中子視圖的約束
[contentView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(contentView).offset(20);
make.bottom.equalTo(contentView).offset(-20);
make.width.equalTo(scrollView).offset(-40);
if (previousView) {
make.left.mas_equalTo(previousView.mas_right).offset(40);
} else {
make.left.mas_equalTo(20);
}
}];
previousView = label;
}
- 設(shè)置 contentView 的right約束,這個(gè)是很關(guān)鍵的位置
//設(shè)置將影響到scrollView的contentSize
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(previousView.mas_right).offset(20);
}];
運(yùn)行結(jié)果如下

垂直方向滑動(dòng)
垂直方向上跟水平方向上的實(shí)現(xiàn)方式大致相同,我就直接粘代碼過(guò)來(lái)了
@interface Demo3ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end
@implementation Demo3ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createDemo];
}
- (void)createDemo {
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = UIColor.greenColor;
[self.view addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.right.mas_equalTo(-10.0);
make.height.mas_equalTo(self.view).offset(-100);
}];
UIView *superView = [[UIView alloc] init];
superView.backgroundColor = UIColor.greenColor;
[scrollView addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(scrollView).with.insets(UIEdgeInsetsZero);
make.width.mas_equalTo(scrollView);
}];
UIButton *button = [[UIButton alloc] init];
[button setTitle:@"增加" forState:UIControlStateNormal];
button.backgroundColor = UIColor.redColor;
[button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
[superView addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0);
make.height.mas_equalTo(100);
make.top.mas_equalTo(20);
}];
self.superView = superView;
self.bottomView = button;
//設(shè)置 scrollview 的 contentSize
[self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
}];
}
static int num = 0;
- (void)action:(UIButton *)button {
//取消底部約束
[self.bottom uninstall];
num += 1;
YYLabel *view = [[YYLabel alloc] init];
view.backgroundColor = UIColor.redColor;
view.text = [NSString stringWithFormat:@"控件%d", num];
view.textAlignment = NSTextAlignmentCenter;
view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
[self.superView addSubview:view];
//給新 view 添加約束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.superView).offset(20);
make.right.mas_equalTo(self.superView).offset(-20);
make.height.mas_equalTo(100);
make.top.mas_equalTo(self.bottomView.mas_bottom).offset(20);
}];
//記錄最下面的 view
self.bottomView = view;
//設(shè)置新的 contentSize
[self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
}];
}
結(jié)果如下

masonry 多列等寬
固定間距
masonry提供了實(shí)現(xiàn)多列等高API,指定 item 之間的間距,然后 item 的寬或者高動(dòng)態(tài)變化
/**
* distribute with fixed spacing
*
* @param axisType which axis to distribute items along
* @param fixedSpacing the spacing between each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
用法如下
- (void)createDemo {
NSMutableArray *views = [NSMutableArray array];
for (NSInteger i = 0; i < 3; i++) {
YYLabel *item = [[YYLabel alloc] init];
view.backgroundColor = UIColor.greenColor;
view.textAlignment = NSTextAlignmentCenter;
view.text = [NSString stringWithFormat:@"%ld",i];
[views addObject:item];
[self.view addSubview:item];
}
[views mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self.view);
make.height.mas_equalTo(100);
}];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedSpacing:50
leadSpacing:10
tailSpacing:20];
}

固定 item 寬度
masonry提供了實(shí)現(xiàn)多列等高API,指定 item 寬度或者高度,然后 item 之間的間距動(dòng)態(tài)變化,方法描述
/**
* distribute with fixed item size
*
* @param axisType which axis to distribute items along
* @param fixedItemLength the fixed length of each item
* @param leadSpacing the spacing before the first item and the container
* @param tailSpacing the spacing after the last item and the container
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
用法
- (void)createDemo {
NSMutableArray *views = [NSMutableArray array];
for (NSInteger i = 0; i < 3; i++) {
YYLabel *item = [[YYLabel alloc] init];
item.backgroundColor = UIColor.greenColor;
item.textAlignment = NSTextAlignmentCenter;
item.text = [NSString stringWithFormat:@"%ld",i];
[views addObject:item];
[self.view addSubview:item];
}
[views mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(self.view);
make.height.mas_equalTo(100);
}];
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedItemLength:100
leadSpacing:50
tailSpacing:50];
}

masonry 設(shè)置寬高比例
在 masonry 提供了multipliedBy()函數(shù)用來(lái)處理布局比例問(wèn)題
,API
/**
* Sets the NSLayoutConstraint multiplier property
*/
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;
用法
- (void)createDemo {
//示例1
YYLabel *superView = [[YYLabel alloc] init];
superView.text = @"示例2";
superView.textAlignment = NSTextAlignmentCenter;
superView.backgroundColor = UIColor.redColor;
[self.view addSubview:superView];
[superView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
//superView.width = superView.height = self.view.width * 0.5;
make.width.height.mas_equalTo(self.view.mas_width).multipliedBy(0.5);
}];
//示例2
YYLabel *subView = [[YYLabel alloc] init];
subView.text = @"示例2";
subView.textAlignment = NSTextAlignmentCenter;
subView.backgroundColor = UIColor.blueColor;
[superView addSubview:subView];
[subView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(0);
make.width.mas_equalTo(superView);
//subView.height = subView.width * 0.5;
make.height.mas_equalTo(subView.mas_width).multipliedBy(0.5);
}];
}
運(yùn)行結(jié)果如下

masonry UIButton 自適應(yīng)寬度
在 UIButton 自使用中需要使用到 mas_greaterThanOrEqualTo(value) 以及 mas_lessThanOrEqualTo(value)方法,mas_greaterThanOrEqualTo(value) 大于等于 value,mas_lessThanOrEqualTo(value)則是小于等于value
示例如下
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"UIButton寬度" forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"icon"] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.view);
make.height.mas_equalTo(@[btn.titleLabel.mas_height, btn.imageView.mas_height]);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
clicked:方法實(shí)現(xiàn)
- (void)clicked:(UIButton *)btn {
[btn setTitle:[btn.currentTitle stringByAppendingString:@"自適應(yīng)"] forState:UIControlStateNormal];
}
看看效果怎么樣

UIButton 還有很多玩法,這里就不一一舉例了
masonry UILabel 自適應(yīng)寬度/高度
- 對(duì)于 UILabel 自適應(yīng)寬度只需要使用
mas_lessThanOrEqualTo()方法就能達(dá)到 - 當(dāng)寬度達(dá)到極限后開(kāi)始換行需要設(shè)置兩個(gè)參數(shù),UILabel的 numberOfLines 屬性和 preferredMaxLayoutWidth 屬性,
代碼實(shí)現(xiàn)
//普通文本
- (void)createDemo {
self.label2 = [[UILabel alloc]init];
self.label2.tag = 100;
[self.view addSubview:self.label2];
self.label2.text = @"最近是用Masonry";
self.label2.backgroundColor = UIColor.redColor;
[self.label2 setPreferredMaxLayoutWidth:self.view.width - 30];
self.label2.numberOfLines = 0;
[self.label2 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.label2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.left.mas_equalTo(15);
}];
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"添加文字" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.label2.mas_bottom).mas_offset(20);
make.centerX.mas_equalTo(self.view);
make.height.mas_equalTo(50);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
}
- (void)clicked {
self.label2.text = [self.label2.text stringByAppendingString:@"Masonry自動(dòng)布局UILabel"];
}
結(jié)果如下

masonry YYLabel 自適應(yīng)寬度/高度
代碼實(shí)現(xiàn)
- (void)createDemo {
self.label1 = [[YYLabel alloc] init];
self.label1.text = @"最近是用Masonry自動(dòng)布局UILabel的時(shí)候,;這些東西之后,label還是沒(méi)有換行。最近是用Masonry自動(dòng)布局UILabel的時(shí)候,";
self.label1.backgroundColor = UIColor.greenColor;
self.label1.numberOfLines = 0;
self.label1.preferredMaxLayoutWidth = self.view.width - 30;
[self.view addSubview:self.label1];
[self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
make.left.mas_equalTo(15);
}];
UIButton *btn = [[UIButton alloc] init];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"添加文字" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.label1.mas_bottom).mas_offset(20);
make.centerX.mas_equalTo(self.view);
make.height.mas_equalTo(50);
make.width.mas_lessThanOrEqualTo(kScreenWidth);
}];
}
- (void)clicked {
self.label1.text = [self.label1.text stringByAppendingString:@"Masonry自動(dòng)布局YYLabel"];
}
結(jié)果如下

masonry 實(shí)現(xiàn)動(dòng)態(tài) UITabelViewCell
先看效果

demo實(shí)現(xiàn)得很粗糙,但是基本功能都實(shí)現(xiàn)了。實(shí)現(xiàn)動(dòng)態(tài) UITabelViewCell 需要了解到的知識(shí)點(diǎn)
- 不設(shè)置cell的高度
- 不實(shí)現(xiàn)返回cell高度的代理方法
- 設(shè)置 UITabelViewCell的estimatedRowHeight屬性
- 將tableview的rowHeight屬性設(shè)置為UITableViewAutomaticDimension
示例如下
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.estimatedRowHeight = 100;
_tableView.rowHeight = UITableViewAutomaticDimension;
[_tableView registerClass:Demo8Cell.class forCellReuseIdentifier:@"cellID"];
[self.view addSubview:_tableView];
}
return _tableView;
}
關(guān)于 tableview 需要設(shè)置的就這些,剩下的在 tableviewCell 的動(dòng)態(tài)高度在cell內(nèi)部設(shè)置
關(guān)于 Demo8Cell 內(nèi)部實(shí)現(xiàn)如下
.h
@class Demo8Model;
NS_ASSUME_NONNULL_BEGIN
@interface Demo8Cell : UITableViewCell
@property (nonatomic, strong) UILabel *messageLabel;
- (void)setmessage:(Demo8Model *)message;
@end
.m
@interface Demo8Cell ()
@property (nonatomic, strong) UIView *picContentView;
@property (nonatomic, strong) UIView *timerView;
@property (nonatomic, strong) UIView *likeView;
@end
@implementation Demo8Cell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self createUI];
}
return self;
}
- (void)createUI {
self.messageLabel = [[UILabel alloc] init];
self.messageLabel.numberOfLines = 0;
[self.contentView addSubview:self.messageLabel];
[self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(8);
make.left.mas_equalTo(10);
make.right.mas_equalTo(-10);
}];
self.picContentView = [[UIView alloc]init];
self.picContentView.backgroundColor = UIColor.grayColor;
[self.contentView addSubview:self.picContentView];
[self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.messageLabel.mas_bottom).offset(15);
make.left.mas_offset(50);
make.right.mas_offset(-20);
}];
self.timerView = [[UIView alloc]init];
self.timerView.backgroundColor = UIColor.redColor;
[self.contentView addSubview:self.timerView];
[self.timerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
make.left.mas_equalTo(50);
make.height.mas_equalTo(30);
make.width.mas_equalTo(50);
//關(guān)鍵位置
make.bottom.mas_equalTo(-8);
}];
self.likeView = [[UIView alloc] init];
self.likeView.backgroundColor = UIColor.redColor;
[self.contentView addSubview:self.likeView];
[self.likeView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
make.right.mas_equalTo(-20);
make.height.mas_equalTo(30);
make.width.mas_equalTo(50);
}];
}
- (void)setmessage:(Demo8Model *)message {
// 創(chuàng)建一個(gè)可變屬性字符串
NSMutableAttributedString *finalStr = [[NSMutableAttributedString alloc] init];
// 創(chuàng)建姓名
NSAttributedString *nameStr = [[NSAttributedString alloc] initWithString:message.name attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]}];
// 創(chuàng)建發(fā)言內(nèi)容
NSAttributedString *messageStr = [[NSAttributedString alloc] initWithString:message.message attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor blackColor]}];
// 拼接上兩個(gè)字符串
[finalStr appendAttributedString:nameStr];
[finalStr appendAttributedString:messageStr];
self.messageLabel.attributedText = finalStr;
//移除所有圖片
[self.picContentView removeAllSubviews];
[self createDemo:message.picNum];
}
- (void)createDemo:(NSInteger)itemNum {
//假設(shè)要顯示 num 個(gè)item
NSInteger num = itemNum;
//每行顯示的個(gè)數(shù)
NSInteger count = 3;
//顯示的總行數(shù)
NSInteger rowNum = (num/count) + ((NSInteger)(num%count>0));
UIView *lastView = nil;
for (int i = 0; i < rowNum; i ++) {
NSMutableArray *masonryViewArray = [NSMutableArray array];
for (int j = 0; j < count; j ++) {
UIView *view = [[UIView alloc] init];
if ((i * count) + j > num-1) {
view.backgroundColor = [UIColor clearColor];
} else {
view.backgroundColor = [UIColor redColor];
}
[self.picContentView addSubview:view];
[masonryViewArray addObject:view];
lastView = view;
}
// 固定 item 之間的間距,item 的寬或者高自動(dòng)縮放
[masonryViewArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:30 leadSpacing:10 tailSpacing:10];
// 設(shè)置array的垂直方向的約束
[masonryViewArray mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@((100 * i) + 10));
make.height.equalTo(@80);
}];
}
if (lastView) {
[self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(lastView.mas_bottom).mas_offset(20);
}];
}
}
@end