- GitHub: Masonry
- star: 17.7k
注:以下內(nèi)容來(lái)源于官方源碼、 README 文檔、測(cè)試 Demo或個(gè)人使用總結(jié) !
Masonry 是一個(gè)輕量級(jí)的布局框架,擁有自己的描述語(yǔ)法,采用優(yōu)雅的鏈?zhǔn)秸Z(yǔ)法來(lái)封裝自動(dòng)布局,簡(jiǎn)潔明了并具有高可讀性。
Masonry 利用簡(jiǎn)化、可鏈接和表達(dá)式的語(yǔ)法發(fā)揮 Auto Layout 和 NSLayoutConstraints
的力量。支持 iOS 和 Mac OS 系統(tǒng)的自動(dòng)布局 。
總的來(lái)說(shuō),就是當(dāng)你在 Interface Bulider 上使用 Auto Layout 的時(shí)候是非常方便的。但是,當(dāng)我們的視圖通過(guò)手寫(xiě)代碼生成時(shí),或是UI界面需要隨用戶(hù)交互而更改,這時(shí)候使用原生的 NSLayoutConstraints
類(lèi)實(shí)現(xiàn)自動(dòng)布局及其繁瑣,Masonry 用簡(jiǎn)潔的語(yǔ)法對(duì) Auto Layout 進(jìn)行了封裝,使用相對(duì)更方便。
NSLayoutConstraints 的問(wèn)題
添加一個(gè)子視圖,跟隨父視圖的大小變化,但是與父視圖邊距有10個(gè)點(diǎn)的距離:
使用 NSLayoutConstraints
- (void)viewDidLoad {
[super viewDidLoad];
UIView *superview = self.view;
UIView *view1 = [[UIView alloc] init];
// 設(shè)置為NO,表示通過(guò)添加自己的約束以使用 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);
}];
更短的寫(xiě)法
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
Masonry 實(shí)踐
下面參考Masonry介紹與使用實(shí)踐(快速上手Autolayout) @里脊串的開(kāi)發(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) {
// 寫(xiě)法一
make.edges.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
/** 寫(xiě)法二
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);
**/
/** 寫(xiě)法三
make.top.left.bottom.and.right.equalTo(superview).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
**/
}];
3. 讓兩個(gè)高度為 150 的視圖垂直居中、等寬、等間隔排列 (間隔為10 ),自動(dòng)計(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并自動(dòng)計(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
類(lèi)中的兩個(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 類(lèi):
- 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í)例測(cè)試:
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];
//給予不同的大小,測(cè)試結(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
屬性必須是對(duì)同一個(gè)控件本身,如果修改成相對(duì)于其它控件會(huì)導(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)先級(jí)屬性來(lái)做簡(jiǎn)單的動(dòng)畫(huà)
.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)滿(mǎn)足高優(yōu)先級(jí)約束
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];
}];
}
注釋?zhuān)狐S色視圖的left屬性分別設(shè)置了兩個(gè)約束,一個(gè)相對(duì)于藍(lán)色視圖的高優(yōu)先級(jí)約束:make.left.mas_equalTo(self.blueView.mas_right).with.offset(40);
另一個(gè)相對(duì)于紅色視圖的低優(yōu)先級(jí)約束:make.left.mas_equalTo(redView.mas_right).with.offset(20).priority(250);
當(dāng)藍(lán)色視圖存在時(shí),兩個(gè)約束同時(shí)存在,為避免約束沖突,系統(tǒng)默認(rèn)滿(mǎn)足高優(yōu)先級(jí)的約束;
當(dāng)點(diǎn)擊屏幕,藍(lán)色視圖被移除后,低優(yōu)先級(jí)的約束就會(huì)生效。
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)先級(jí)最低 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檢測(cè)是否需要更新約束,若需要?jiǎng)t更新。下面添加的動(dòng)畫(huà)效果才起作用 [self.view updateConstraintsIfNeeded]; [UIView animateWithDuration:0.3 animations:^{ [self.view layoutIfNeeded]; }]; }
-
更新約束:
// 這是Apple推薦的添加/更新約束的地方 // 此方法可以被多次調(diào)用,以響應(yīng) setNeedsUpdateConstraints // 如果您需要觸發(fā)對(duì)約束的更新,可以在UIKit內(nèi)部或你的代碼中調(diào)用該方法 - (void)updateViewConstraints { [self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) { //這里寫(xiě)需要更新的約束,不用更新的約束將繼續(xù)存在,并不會(huì)被取代 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;
// 重寫(xiě)當(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)會(huì)調(diào)用 updateConstraints()方法,修改多個(gè)約束后調(diào)用該方法批量更新有助于提升性能
- (void)setNeedsUpdateConstraints;
// 當(dāng)前是否需要重新布局,內(nèi)部會(huì)判斷當(dāng)前有沒(méi)有被標(biāo)記的約束
- (BOOL)needsUpdateConstraints;
// 調(diào)用此方法,如果有標(biāo)記為需要重新布局的約束,則立即進(jìn)行重新布局,內(nèi)部會(huì)調(diào)用 updateConstraints方法
- (void)updateConstraintsIfNeeded;
// 重寫(xiě)此方法,內(nèi)部實(shí)現(xiàn)自定義布局過(guò)程
- (void)updateConstraints;
9.Masonry的重寫(xiě)約束: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)我展開(kāi)" 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)我展開(kāi)" 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會(huì)將之前的約束全部移除,然后重新添加
__weak typeof (self)weakself = self;
[self.growingButton mas_remakeConstraints:^(MASConstraintMaker *make) {
// 重寫(xiě)全部約束
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è)簡(jiǎn)化代碼的宏:
#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ù)類(lèi)型, 內(nèi)部會(huì)對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行包裝注意:這兩個(gè)宏如果想有效使用,必須要在添加Masonry頭文件之前導(dǎo)入進(jìn)去。在沒(méi)有增加宏
MAS_SHORTHAND_GLOBALS
時(shí),下面這句是會(huì)報(bào)錯(cuò)的。
make.top.equalTo(42); --> make.top.equalTo([NSNumber numberWithInt:42]);
? ——摘自Masonry使用總結(jié)
注意:有時(shí)候?qū)懠s束語(yǔ)法的時(shí)候 with 經(jīng)常會(huì)不小心寫(xiě)成 width,就像這樣:
make.bottom.mas_equalTo(self.view.mas_bottom).width.offset(-80);
于是會(huì)報(bào)這樣的錯(cuò)誤:
Attributes should be chained before defining the constraint relation.
屬性應(yīng)該在定義約束關(guān)系之前鏈接.
記得仔細(xì)查找這種錯(cuò)誤并改正。
參考文章
- GitHub:Masonry
- GitHub:MMPlaceHolder
- GitHub:DemoMasonry
- iOS AutoLayout與AutoSizing:自動(dòng)布局,想說(shuō)愛(ài)你真的好難
- Masonry介紹與使用實(shí)踐(快速上手Autolayout) @里脊串的開(kāi)發(fā)隨筆 ??????
- Masonry使用總結(jié) ??????
- 簡(jiǎn)書(shū):iOS自動(dòng)布局框架-Masonry詳解 @劉小壯
- Masonry:使用純代碼進(jìn)行iOS應(yīng)用的autolayout自適應(yīng)布局 @伯樂(lè)在線(xiàn)
- iOS自適應(yīng)前段庫(kù)-Masonry的使用