- GitHub: Masonry
- star: 17.7k
注:以下內(nèi)容來源于官方源碼、 README 文檔、測試 Demo或個(gè)人使用總結(jié) !
Masonry 是一個(gè)輕量級的布局框架,擁有自己的描述語法,采用優(yōu)雅的鏈?zhǔn)秸Z法來封裝自動布局,簡潔明了并具有高可讀性。
Masonry 利用簡化、可鏈接和表達(dá)式的語法發(fā)揮 Auto Layout 和 NSLayoutConstraints
的力量。支持 iOS 和 Mac OS 系統(tǒng)的自動布局 。
總的來說,就是當(dāng)你在 Interface Bulider 上使用 Auto Layout 的時(shí)候是非常方便的。但是,當(dāng)我們的視圖通過手寫代碼生成時(shí),或是UI界面需要隨用戶交互而更改,這時(shí)候使用原生的 NSLayoutConstraints
類實(shí)現(xiàn)自動布局及其繁瑣,Masonry 用簡潔的語法對 Auto Layout 進(jìn)行了封裝,使用相對更方便。
NSLayoutConstraints 的問題
添加一個(gè)子視圖,跟隨父視圖的大小變化,但是與父視圖邊距有10個(gè)點(diǎn)的距離:
使用 NSLayoutConstraints
- (void)viewDidLoad {
[super viewDidLoad];
UIView *superview = self.view;
UIView *view1 = [[UIView alloc] init];
// 設(shè)置為NO,表示通過添加自己的約束以使用 Auto Layout 定位視圖
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
// 指定每個(gè)邊緣的插入量(正),值可以是負(fù)的到“起點(diǎn)”
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
// view1 constraints
// view1.attribute1 = multiplier × superview.attribute2 + constant
// view1的頂部距離父視圖的頂部10px
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
// 左邊距離10px
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
// 底部距離10px
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
// 右邊距離10px
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
]];
}
使用 Masonry
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top);
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
更短的寫法
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
Masonry 實(shí)踐
下面參考Masonry介紹與使用實(shí)踐(快速上手Autolayout) @里脊串的開發(fā)隨筆,練習(xí)使用Masonry。
1. 居中顯示一個(gè) 300*300 的 superview
UIView *superview = [UIView new];
[superview showPlaceHolder]; // 需要導(dǎo)入MMPlaceHolder框架
superview.backgroundColor = [UIColor blackColor];
[self.view addSubview:superview];
[superview mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(300, 300));
}];
2. 讓 superview1 略小于其 superview (邊距為20)
UIView *superview1 =[UIView new];
superview1.backgroundColor = [UIColor redColor];
[superview addSubview:superview1];
[superview1 mas_makeConstraints:^(MASConstraintMaker *make) {
// 寫法一
make.edges.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
/** 寫法二
make.top.equalTo(superview).with.offset(20);
make.left.equalTo(superview).with.offset(20);
make.bottom.equalTo(superview).with.offset(-20);
make.right.equalTo(superview).with.offset(-20);
**/
/** 寫法三
make.top.left.bottom.and.right.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
**/
}];
3. 讓兩個(gè)高度為 150 的視圖垂直居中、等寬、等間隔排列 (間隔為10 ),自動計(jì)算其寬度
UIView *superview2 =[UIView new];
superview2.backgroundColor = [UIColor orangeColor];
[superview addSubview:superview2];
UIView *superview3 =[UIView new];
superview3.backgroundColor = [UIColor orangeColor];
[superview addSubview:superview3];
int padding1 = 10;
[superview2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(superview.mas_centerY);
make.left.equalTo(superview.mas_left).with.offset(padding1);
make.right.equalTo(superview3.mas_left).with.offset(-padding1);
make.height.mas_equalTo(@150);
make.width.equalTo(superview3);
}];
[superview3 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(superview.mas_centerY);
make.left.equalTo(superview2.mas_right).with.offset(padding1);
make.right.equalTo(superview.mas_right).with.offset(-padding1);
make.height.mas_equalTo(@150);
make.width.equalTo(superview2);
}];
4. 在UIScrollView 上順序排列一些view并自動計(jì)算contentSize
UIScrollView *scrollView = [UIScrollView new];
scrollView.backgroundColor = [UIColor whiteColor];
[superview addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(UIEdgeInsetsMake(5, 5, 5, 5));
}];
UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(scrollView);
make.width.equalTo(scrollView);
}];
int count = 10;
UIView *lastView = nil;
for (int i = 1; i <= count; i++) {
UIView *subView = [UIView new];
[container addSubview:subView];
subView.backgroundColor = [UIColor colorWithHue:(arc4random() % 256 / 256.0)
saturation:(arc4random() % 128 / 256.0) + 0.5
brightness:(arc4random() % 128 / 256.0) + 0.5
alpha:1];
[subView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.and.right.equalTo(container);
make.height.mas_equalTo(@(20 * i)); // 每個(gè)子視圖的高度是20的倍數(shù)
if (lastView) {
// 下一個(gè)子視圖的頂部 = 上一個(gè)子視圖的底部
make.top.mas_equalTo(lastView.mas_bottom);
}else {
// 第一次執(zhí)行,lastView = nil,因此第一個(gè)子視圖的頂部是容器的頂部
make.top.mas_equalTo(container.mas_top);
}
}];
lastView = subView;
}
[container mas_makeConstraints:^(MASConstraintMaker *make) {
// 容器的底部是最后一個(gè)視圖的底部
make.bottom.equalTo(lastView.mas_bottom);
}];
5. 橫向或者縱向等間隙的排列一組view
11/15 添加
均勻分布一組view推薦使用NSArray+MASAdditions.h
類中的兩個(gè)方法:
/**
* 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;
/**
* 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;
需要使用封裝的 category 類:
- UIView+LJC.h:
#import <UIKit/UIKit.h>
/**
橫向或者縱向等間隙的排列一組view
*/
@interface UIView (LJC)
- (void) distributeSpacingHorizontallyWith:(NSArray*)views;
- (void) distributeSpacingVerticallyWith:(NSArray*)views;
@end
- UIView+LJC.m:
#import "UIView+LJC.h"
#import <Masonry/Masonry.h>
@implementation UIView (LJC)
/**
橫向排列一組view
@param views view數(shù)組
*/
- (void) distributeSpacingHorizontallyWith:(NSArray*)views
{
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
for ( int i = 0 ; i < views.count+1 ; ++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[0];
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.mas_left);
make.centerY.equalTo(((UIView*)views[0]).mas_centerY);
}];
UIView *lastSpace = v0;
for ( int i = 0 ; i < views.count; ++i )
{
UIView *obj = views[i];
UIView *space = spaces[i+1];
[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(self.mas_right);
}];
}
/**
垂直排列一組view
@param views view數(shù)組
*/
- (void) distributeSpacingVerticallyWith:(NSArray*)views
{
NSMutableArray *spaces = [NSMutableArray arrayWithCapacity:views.count+1];
for ( int i = 0 ; i < views.count+1 ; ++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[0];
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_top);
make.centerX.equalTo(((UIView*)views[0]).mas_centerX);
}];
UIView *lastSpace = v0;
for ( int i = 0 ; i < views.count; ++i )
{
UIView *obj = views[i];
UIView *space = spaces[i+1];
[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(self.mas_bottom);
}];
}
@end
- 實(shí)例測試:
UIView *subView11 = [UIView new];
UIView *subView12 = [UIView new];
UIView *subView13 = [UIView new];
UIView *subView21 = [UIView new];
UIView *subView31 = [UIView new];
subView11.backgroundColor = [UIColor redColor];
subView12.backgroundColor = [UIColor redColor];
subView13.backgroundColor = [UIColor redColor];
subView21.backgroundColor = [UIColor redColor];
subView31.backgroundColor = [UIColor redColor];
[superview addSubview:subView11];
[superview addSubview:subView12];
[superview addSubview:subView13];
[superview addSubview:subView21];
[superview addSubview:subView31];
//給予不同的大小,測試結(jié)果
[subView11 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(@[subView12,subView13]); // 11、12、13 Y方向?qū)R
make.centerX.equalTo(@[subView21,subView31]); // 11、21、31 X方向?qū)R
make.size.mas_equalTo(CGSizeMake(40, 40));
}];
[subView12 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(30, 30));
}];
[subView13 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(20, 20));
}];
[subView21 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(50, 50));
}];
[subView31 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(60, 60));
}];
[superview distributeSpacingHorizontallyWith:@[subView11,subView12,subView13]];
[superview distributeSpacingVerticallyWith:@[subView11,subView21,subView31]];
[superview showPlaceHolderWithAllSubviews];
[superview hidePlaceHolder];
使用空白的占位view填充目標(biāo)view的旁邊
繼續(xù)參考:Masonry使用總結(jié),學(xué)習(xí)使用 Masonry;
6. Masonry 中的比例 multipliedBy
使用 multipliedBy
屬性必須是對同一個(gè)控件本身,如果修改成相對于其它控件會導(dǎo)致 Crash。
UIView *topView = [UIView new];
[topView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:topView];
UIView *topInnerView = [UIView new];
[topInnerView setBackgroundColor:[UIColor greenColor]];
[topInnerView showPlaceHolder];
[self.view addSubview:topInnerView];
UIView *bottomView =[UIView new];
[bottomView setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:bottomView];
UIView *bottomInnerView =[UIView new];
[bottomInnerView setBackgroundColor:[UIColor blackColor]];
[bottomInnerView showPlaceHolder];
[self.view addSubview:bottomInnerView];
[topView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.and.right.mas_equalTo(0);
make.height.mas_equalTo(bottomView);
}];
[topInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.and.right.mas_equalTo(0);
make.width.mas_equalTo(topInnerView.mas_height).multipliedBy(3);
make.center.mas_equalTo(topView);
}];
[bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.bottom.and.right.mas_equalTo(0);
make.height.mas_equalTo(topView);
make.top.mas_equalTo(topView.mas_bottom);
}];
[bottomInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.and.bottom.mas_equalTo(bottomView);
make.height.mas_equalTo(bottomInnerView.mas_width).multipliedBy(3);
make.center.mas_equalTo(bottomView);
}];
7. 使用 priority
優(yōu)先級屬性來做簡單的動畫
.priority allows you to specify an exact priority
.priorityHigh equivalent to UILayoutPriorityDefaultHigh
.priorityMedium is half way between high and low
.priorityLow equivalent to UILayoutPriorityDefaultLow
- 先為blueView設(shè)置屬性:
@interface ViewController ()
@property (nonatomic,strong) UIView *blueView;
@end
2.創(chuàng)建視圖并設(shè)置約束:
// 紅色視圖
UIView *redView = [UIView new];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
// 藍(lán)色視圖
self.blueView = [UIView new];
self.blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.blueView];
// 黃色視圖
UIView *yellowView = [UIView new];
yellowView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:yellowView];
// ————紅色視圖約束————
[redView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view.mas_left).with.offset(20);
make.bottom.mas_equalTo(self.view.mas_bottom).with.offset(-80);
make.height.mas_equalTo(50);
}];
// ————藍(lán)色視圖約束————
[self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(redView.mas_right).with.offset(40);
make.bottom.width.and.height.with.height.mas_equalTo(redView);
}];
// ————黃色視圖約束————
[yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
// 默認(rèn)滿足高優(yōu)先級約束
make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);
make.right.mas_equalTo(self.view.mas_right).with.offset(-20);
make.bottom.width.and.height.mas_equalTo(redView);
//** priority設(shè)置為250,最高1000(默認(rèn))**
make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);
}];
3.點(diǎn)擊屏幕移除藍(lán)色視圖方法:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.blueView removeFromSuperview];
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
}
注釋:黃色視圖的left屬性分別設(shè)置了兩個(gè)約束,一個(gè)相對于藍(lán)色視圖的高優(yōu)先級約束:make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);
另一個(gè)相對于紅色視圖的低優(yōu)先級約束:make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);
當(dāng)藍(lán)色視圖存在時(shí),兩個(gè)約束同時(shí)存在,為避免約束沖突,系統(tǒng)默認(rèn)滿足高優(yōu)先級的約束;
當(dāng)點(diǎn)擊屏幕,藍(lán)色視圖被移除后,低優(yōu)先級的約束就會生效。
8.Masonry更新約束方法:mas_updateConstraints
如果你只想更新約束的常量值,則可以使用更方便的方法:mas_updateConstraints
而不是mas_makeConstraints
。
-
創(chuàng)建一個(gè) Button 屬性、scale 屬性用于記錄放大比例:
@interface ViewController () @property (nonatomic,strong) UIButton *growingButton; @property (nonatomic,assign) CGFloat scale; @end
-
創(chuàng)建 Button 實(shí)例:
self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem]; [self.growingButton setTitle:@"點(diǎn)我放大" forState:UIControlStateNormal]; self.growingButton.layer.borderColor = UIColor.greenColor.CGColor; self.growingButton.layer.borderWidth = 3; [self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.growingButton]; self.scale = 1.0; [self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) { make.center.mas_equalTo(self.view); // 初始寬、高為100,優(yōu)先級最低 make.width.height.mas_equalTo(100 * self.scale); // 最大放大到整個(gè)view make.width.and.height.lessThanOrEqualTo(self.view); }]
-
點(diǎn)擊 Button 方法:
- (void)onGrowButtonTaped:(UIButton *)sender { self.scale += 1.0; //告訴self.view約束需要更新 [self.view setNeedsUpdateConstraints]; //調(diào)用此方法告訴self.view檢測是否需要更新約束,若需要則更新。下面添加的動畫效果才起作用 [self.view updateConstraintsIfNeeded]; [UIView animateWithDuration:0.3 animations:^{ [self.view layoutIfNeeded]; }]; }
-
更新約束:
// 這是Apple推薦的添加/更新約束的地方 // 此方法可以被多次調(diào)用,以響應(yīng) setNeedsUpdateConstraints // 如果您需要觸發(fā)對約束的更新,可以在UIKit內(nèi)部或你的代碼中調(diào)用該方法 - (void)updateViewConstraints { [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) { //這里寫需要更新的約束,不用更新的約束將繼續(xù)存在,并不會被取代 make.width.and.height.mas_equalTo(100*self.scale); }]; // //根據(jù)Apple要求,super方法應(yīng)該在方法結(jié)束時(shí)調(diào)用 [super updateViewConstraints]; }
?
代碼執(zhí)行順序:
-[ViewController viewDidLoad]
-[ViewController createGrowingButton]
mas_makeConstraints
-[ViewController updateViewConstraints]
mas_updateConstraints
點(diǎn)擊按鈕
-[ViewController onGrowButtonTaped:]
-[ViewController updateViewConstraints]
mas_updateConstraints
點(diǎn)擊按鈕
-[ViewController onGrowButtonTaped:]
-[ViewController updateViewConstraints]
mas_updateConstraints
更新約束和布局的相關(guān)方法
- 關(guān)于
UIView
重新布局相關(guān)的 API,主要有以下三個(gè):
// 標(biāo)記為需要在下一個(gè)周期重新布局
- (void)setNeedsLayout;
// 查看當(dāng)前視圖是否被標(biāo)記需要重新布局,有則在內(nèi)部調(diào)用layoutSubviews方法立即進(jìn)行重新布局
- (void)layoutIfNeeded;
// 重寫當(dāng)前方法,在內(nèi)部完成重新布局操作,不要直接調(diào)用,如果需要強(qiáng)制更新布局,調(diào)用 setNeedsLayout()
- (void)layoutSubviews;
- 關(guān)于更新約束布局相關(guān)的 API,主要有以下四個(gè):
// 標(biāo)記需要進(jìn)行重新布局,系統(tǒng)會調(diào)用 updateConstraints()方法,修改多個(gè)約束后調(diào)用該方法批量更新有助于提升性能
- (void)setNeedsUpdateConstraints;
// 當(dāng)前是否需要重新布局,內(nèi)部會判斷當(dāng)前有沒有被標(biāo)記的約束
- (BOOL)needsUpdateConstraints;
// 調(diào)用此方法,如果有標(biāo)記為需要重新布局的約束,則立即進(jìn)行重新布局,內(nèi)部會調(diào)用 updateConstraints方法
- (void)updateConstraintsIfNeeded;
// 重寫此方法,內(nèi)部實(shí)現(xiàn)自定義布局過程
- (void)updateConstraints;
9.Masonry的重寫約束:mas_remakeConstraints
mas_updateConstraints
is useful for updating a set of constraints, but doing anything beyond updating constant values can get exhausting. That's wheremas_remakeConstraints
comes in.
mas_remakeConstraints
is similar tomas_updateConstraints
, but instead of updating constant values, it will remove all of its constraints before installing them again. This lets you provide different constraints without having to keep around references to ones which you want to remove.
- 創(chuàng)建一個(gè)Button屬性、isExpanded屬性用于記錄按鈕狀態(tài):
@property (nonatomic,strong) UIButton *growingButton;
@property (nonatomic,assign) BOOL isExpanded;
- 創(chuàng)建Button實(shí)例:
self.isExpanded = NO;
self.growingButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.growingButton setTitle:@"點(diǎn)我展開" forState:UIControlStateNormal];
self.growingButton.layer.borderColor = UIColor.greenColor.CGColor;
self.growingButton.layer.borderWidth = 3;
self.growingButton.backgroundColor = [UIColor redColor];
[self.growingButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_growingButton];
[self.growingButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.and.left.mas_equalTo(100);
make.bottom.mas_equalTo(-350);
make.right.mas_equalTo(-100);
}];
- 點(diǎn)擊Button方法:
- (void)onGrowButtonTaped:(UIButton *)sender {
self.isExpanded = !self.isExpanded;
if (!self.isExpanded) {
[self.growingButton setTitle:@"點(diǎn)我展開" forState:UIControlStateNormal];
}else {
[self.growingButton setTitle:@"點(diǎn)我收起" forState:UIControlStateNormal];
}
[self.view setNeedsUpdateConstraints];
[self.view updateConstraintsIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}
- 更新約束:
- (void)updateViewConstraints {
NSLog(@"%s",__func__);
// 這里使用update也能實(shí)現(xiàn)效果,而remark會將之前的約束全部移除,然后重新添加
__weak typeof (self)weakself = self;
[self.growingButton mas_remakeConstraints:^(MASConstraintMaker *make) {
// 重寫全部約束
if (weakself.isExpanded) {
make.top.and.left.mas_equalTo(0);
make.bottom.mas_equalTo(10);
make.right.mas_equalTo(0);
}else {
make.top.and.left.mas_equalTo(100);
make.bottom.mas_equalTo(-350);
make.right.mas_equalTo(-100);
}
}];
[super updateViewConstraints];
}
實(shí)現(xiàn)結(jié)果:
其他
By default, macros which support autoboxing are prefixed with mas_. Unprefixed versions are available by defining MAS_SHORTHAND_GLOBALS before importing Masonry.
? ——摘自Masonary:README.md
- 為了增加代碼的可讀性這里有兩個(gè)簡化代碼的宏:
#define MAS_SHORTHAND
和#define MAS_SHORTHAND_GLOBALS
MAS_SHORTHAND
:只要在導(dǎo)入Masonry主頭文件之前定義這個(gè)宏, 那么以后在使用Masonry框架中的屬性和方法的時(shí)候, 就可以省略mas_前綴
MAS_SHORTHAND_GLOBALS
:只要在導(dǎo)入Masonry主頭文件之前定義這個(gè)宏,那么就可以讓equalTo
函數(shù)接收基本數(shù)據(jù)類型, 內(nèi)部會對基本數(shù)據(jù)類型進(jìn)行包裝注意:這兩個(gè)宏如果想有效使用,必須要在添加Masonry頭文件之前導(dǎo)入進(jìn)去。在沒有增加宏
MAS_SHORTHAND_GLOBALS
時(shí),下面這句是會報(bào)錯(cuò)的。
make.top.equalTo(42); --> make.top.equalTo([NSNumber numberWithInt:42]);
? ——摘自Masonry使用總結(jié)
注意:有時(shí)候?qū)懠s束語法的時(shí)候 with 經(jīng)常會不小心寫成 width,就像這樣:
make.bottom.mas_equalTo(self.view.mas_bottom).width.offset(-80);
于是會報(bào)這樣的錯(cuò)誤:
Attributes should be chained before defining the constraint relation.
屬性應(yīng)該在定義約束關(guān)系之前鏈接.
記得仔細(xì)查找這種錯(cuò)誤并改正。