iOS自動(dòng)布局 - Masonry

Masonry是對AutoLayout封裝而成的一個(gè)輕量級的布局框架朋凉。其語法優(yōu)雅改览、代碼簡潔低滩,可讀性很高,而且同時(shí)支持iOS和Mac OS X欺抗。

這篇文章主要講解Masonry的用法售碳。

1 安裝Masonry

這里我們使用CocoaPods來安裝Masonry。

首先打開Podfile文件绞呈,添加下面的內(nèi)容:

pod 'Masonry'

如果項(xiàng)目中還沒有Podfile文件贸人,可以在當(dāng)前項(xiàng)目中手動(dòng)創(chuàng)建一個(gè),也可以通過終端定位到項(xiàng)目目錄佃声,使用pod init命令創(chuàng)建一個(gè)Podfile文件艺智。

在命令行中輸入pod install安裝Masonry:

$ pod install

如果出現(xiàn)下面的提示內(nèi)容,則表示Masonry安裝成功:

Analyzing dependencies
Downloading dependencies
Installing Masonry (1.1.0)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `MasonryDemo.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

2 Masonry的使用

首先關(guān)閉之前創(chuàng)建的項(xiàng)目文件圾亏,打開后綴名為xcworkspace的項(xiàng)目十拣。在需要使用Masonry的項(xiàng)目文件中導(dǎo)入Masonry的頭文件。

這里我們創(chuàng)建一個(gè)greenView的子視圖志鹃,并將它添加到self.view上夭问,然后使用Masonry對它進(jìn)行布局,讓其距離父視圖的上下左右邊距均為20:

#import "ViewController.h"
#import "Masonry.h"

@interface ViewController ()
@property (nonatomic, strong) UIView *greenView;
@end

@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 添加子視圖
    [self.view addSubview:self.greenView];
    
    // 添加布局
    [self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(20);
        make.right.equalTo(self.view).offset(-20);
        make.top.equalTo(self.view).offset(20);
        make.bottom.equalTo(self.view).offset(-20);
    }];
}

- (UIView *)greenView
{
    if (!_greenView) {
        _greenView = [[UIView alloc] init];
        _greenView.backgroundColor = [UIColor greenColor];
        _greenView.layer.borderColor = [UIColor blackColor].CGColor;
        _greenView.layer.borderWidth = 2.0;
    }
    return _greenView;
}

運(yùn)行結(jié)果:

在上面的代碼中曹铃,我們調(diào)用了mas_makeConstraints:方法給視圖添加布局信息:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.view).offset(20);
    make.left.equalTo(self.view).offset(20);
    make.bottom.equalTo(self.view).offset(-20);
    make.right.equalTo(self.view).offset(-20);
}];

上面的left缰趋、righttop陕见、bottom均是Masonry支持的屬性秘血,分別表示左側(cè)、右側(cè)淳玩、頂部直撤、底部;equalTo表示約束的關(guān)系蜕着;offset表示偏移值谋竖,另外還有multipliedBy表示倍數(shù)值。

上面的代碼也可以寫成:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.mas_equalTo(self.view.mas_top).offset(20);
    make.left.mas_equalTo(self.view.mas_left).offset(20);
    make.bottom.mas_equalTo(self.view.mas_bottom).offset(-20);
    make.right.mas_equalTo(self.view.mas_right).offset(-20);
}];

還可以寫成:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(@20);
    make.left.equalTo(@20);
    make.bottom.equalTo(@-20);
    make.right.equalTo(@-20);
}];

和:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.mas_equalTo(20);
    make.left.mas_equalTo(20);
    make.bottom.mas_equalTo(-20);
    make.right.mas_equalTo(-20);
}];

還可以簡化為:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];

和:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.left.bottom.and.right.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];

值得一提的是承匣,這里的andwith其實(shí)沒有執(zhí)行任何操作蓖乘,實(shí)際上是可以省略的,但是用在這種鏈?zhǔn)秸Z法中就很巧妙韧骗,增加了語句的可讀性嘉抒,而且特別容易理解。

如果不想使用mas_前綴袍暴,可以在導(dǎo)入Masonry之前添加下面的宏:

#define MAS_SHORTHAND

例如:

#define MAS_SHORTHAND

#import "ViewController.h"
#import "Masonry.h"

...
[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
}];

另外些侍,也可以將#define MAS_SHORTHAND寫在PrefixHeader.pch文件中隶症。

創(chuàng)建PrefixHeader.pch文件

打開File\New\File...,選擇iOS\Other\PCH File岗宣,點(diǎn)擊Next蚂会,修改要保存的文件名稱(這里使用默認(rèn)的),點(diǎn)擊Create即可耗式。

然后在PrefixHeader.pch文件中添加下面的代碼:

#define MAS_SHORTHAND

#import "Masonry.h"

這樣下次再需要使用Masonry的時(shí)候就不需要再導(dǎo)入了胁住,并且也可以省略掉mas_前綴。

需要注意的是刊咳,PrefixHeader.pch文件需要配置一下才能生效彪见。

配置PrefixHeader.pch文件

選中項(xiàng)目,然后TARGETS\Build Settings娱挨,然后在搜索框中輸入prefix header余指,然后定位到Apple Clang - Language這一欄,將Precompile Prefix Header的值改為YES让蕾,然后在Prefix Header右側(cè)雙擊浪规,在彈出的輸入框中填寫PrefixHeader.pch文件的路徑即可。

這里可以使用$(SRCROOT)/項(xiàng)目名稱/xxx.pch這樣的格式來設(shè)置路徑探孝,其中$(SRCROOT)表示項(xiàng)目所在的目錄。

3 Masonry支持的屬性

前面代碼中我們用到的left誉裆、right顿颅、topbottom屬性足丢,其實(shí)Masonry還有很多屬性粱腻。

下面列出的是標(biāo)準(zhǔn)屬性:

@property (nonatomic, strong, readonly) MASConstraint *left;
@property (nonatomic, strong, readonly) MASConstraint *top;
@property (nonatomic, strong, readonly) MASConstraint *right;
@property (nonatomic, strong, readonly) MASConstraint *bottom;
@property (nonatomic, strong, readonly) MASConstraint *leading;
@property (nonatomic, strong, readonly) MASConstraint *trailing;
@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *baseline;

除此之外,Masonry還支持margin和safeArea相關(guān)的屬性:

@property (nonatomic, strong, readonly) MASViewAttribute *leftMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *rightMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *topMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *bottomMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *leadingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *trailingMargin;
@property (nonatomic, strong, readonly) MASViewAttribute *centerXWithinMargins;
@property (nonatomic, strong, readonly) MASViewAttribute *centerYWithinMargins;

@property (nonatomic, strong, readonly) MASViewAttribute *safeAreaLayoutGuideTop;
@property (nonatomic, strong, readonly) MASViewAttribute *safeAreaLayoutGuideBottom;
@property (nonatomic, strong, readonly) MASViewAttribute *safeAreaLayoutGuideLeft;
@property (nonatomic, strong, readonly) MASViewAttribute *safeAreaLayoutGuideRight;

另外斩跌,Masonry還提供了一些方便的方法绍些,可以同時(shí)創(chuàng)建多種約束,它們被稱為MASCompositeConstraints(復(fù)合約束):

@property (nonatomic, strong, readonly) MASConstraint *edges;
@property (nonatomic, strong, readonly) MASConstraint *size;
@property (nonatomic, strong, readonly) MASConstraint *center;
  • edges

    make.edges.equalTo(self.view);
    make.edges.mas_equalTo(UIEdgeInsetsMake(20, 20, 20, 20));
    make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(20, 20, 20, 20));
    
  • size

    make.size.greaterThanOrEqualTo(view1);
    make.size.mas_equalTo(CGSizeMake(300, 200));
    
    make.size.equalTo(self.view).sizeOffset(CGSizeMake(100, -50));    
    // 表示:view.width = view.superView.width + 100, view.height = view.superView.height - 50
    
  • center

    make.center.equalTo(self.view);
    make.center.equalTo(@(CGPointMake(100, 200)));
    make.center.mas_equalTo(CGPointMake(100, 200));
    
    make.center.equalTo(self.view).centerOffset(CGPointMake(-5, 10)); 
    // 表示: view.centerX = view.superView.centerX - 5, view.centerY = view.superView.centerY + 10
    

4 Masonry中約束的關(guān)系

  • equalTo
  • lessThanOrEqualTo
  • greaterThanOrEqualTo

如果希望greenView的左側(cè)大于或者等于self.view的左側(cè)耀鸦,我們可以在代碼中可以這樣寫:

[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    make.left.greaterThanOrEqualTo(self.view);
}];

如果希望greenView的寬度大于等于200柬批,小于等于400,我們可以在代碼中這樣寫:

[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    // width >= 200 && width <= 400
    make.width.greaterThanOrEqualTo(@200);
    make.width.lessThanOrEqualTo(@400);
}];

5 Masonry中約束的優(yōu)先級

  • priority可以指定一個(gè)確切的優(yōu)先級值袖订,范圍在0 ~ 1000氮帐,值越大優(yōu)先級越高。
  • priorityHigh相當(dāng)于UILayoutPriorityDefaultHigh洛姑,優(yōu)先級值為750上沐。
  • priorityMedium介于高優(yōu)先級和低優(yōu)先級之間,優(yōu)先級值在250 ~ 750之間楞艾。
  • priorityLow相當(dāng)于UILayoutPriorityDefaultLow参咙,優(yōu)先級值為250龄广。

優(yōu)先級可以寫在約束鏈的末尾,例如:

make.top.equalTo(self.view).with.priority(800);
make.bottom.equalTo(self.view).priorityMedium();
make.left.equalTo(self.view).priorityLow();
make.right.equalTo(self.view).priorityHigh();

6 創(chuàng)建約束

自動(dòng)布局允許將寬度和高度設(shè)置為常量值蕴侧,例如:

[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    make.width.equalTo(@300);
    make.height.equalTo(@200);
}];

但是蜀细,自動(dòng)布局不允許將對齊屬性(如leftright戈盈、centerY等)設(shè)置為常量值奠衔。如果為這些屬性傳遞了一個(gè)NSNumber類型的值,Masonry會(huì)將這些變?yōu)橄鄬τ谝晥D的父視圖的約束塘娶,即:

[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(@10);
}];

相當(dāng)于:

[self.greenView makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(self.view.mas_left).offset(10);
}];

表示:

view.left = view.superView.left + 10;

除了使用NSNumber類型創(chuàng)建約束以外归斤,還可以使用結(jié)構(gòu)等,示例如下:

make.size.equalTo(@(CGSizeMake(300, 200)));
make.size.mas_equalTo(CGSizeMake(300, 200));
make.edges.mas_equalTo(UIEdgeInsetsMake(20, 20, 20, 20));

make.left.mas_equalTo(self.view).mas_offset(UIEdgeInsetsMake(20, 20, 20, 20));  

上面最后一行代碼的效果等同于:

make.left.mas_equalTo(self.view).mas_offset(20);

另外刁岸,還可以使用數(shù)組來傳遞不同類型的值創(chuàng)建約束脏里,例如:

make.height.equalTo(@[view1.mas_height, view2.mas_height]);
make.height.equalTo(@[view1, view2]);
make.left.equalTo(@[view1.right, @100, view2]);

7 使用Masonry更新約束

有時(shí)候我們需要更改現(xiàn)有的約束以設(shè)置動(dòng)畫,或者刪除虹曙、替換約束迫横,在Mansory中,我們可以使用下面的方法來更新約束酝碳。

7.1 將約束的表達(dá)式結(jié)果保存為屬性或變量矾踱,通過使用該約束變量或?qū)傩詠硖砑踊蛘邉h除約束。

例如疏哗,我們可以聲明一個(gè)MASConstraint類型的屬性:

@property (nonatomic, strong) MASConstraint *topConstraint;

然后定義該屬性:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    self.topConstraint = make.top.equalTo(self.view).with.offset(20);
}];

后面如果需要重新該約束值呛讲,可以這樣寫:

self.topConstraint.mas_equalTo(20);

另外,還可以根據(jù)需要調(diào)用下面的方法:

[self.topConstraint install];   // 創(chuàng)建NSLayoutConstraint并將其添加到適當(dāng)?shù)囊晥D上返奉。
[self.topConstraint uninstall]; // 刪除之前安裝的NSLayoutConstraint
[self.topConstraint activate];  // 如果操作系統(tǒng)支持NSLayoutConstraint贝搁,可以調(diào)用該方法來激活約束。否則需要調(diào)用install方法芽偏。
[self.topConstraint deactivate];    // 取消激活(使無效)之前安裝/激活的NSLayoutConstraint雷逆。

以之前的greenView為例,我們在self.view上添加一個(gè)點(diǎn)擊手勢污尉,每次點(diǎn)擊的時(shí)候更新greenView的edges約束:

@property (nonatomic, strong) MASConstraint *edgesConstraint;

- (void)viewDidLoad
{
    ...
    
    // 添加子視圖
    [self.view addSubview:self.greenView];
    
    // 給self.view添加點(diǎn)擊手勢
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
    [self.view addGestureRecognizer:tap];
    
    // 給greenView添加布局
    [self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
        self.edgesConstraint = make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
    }];
}

- (void)tap:(UITapGestureRecognizer *)tap
{
    int i = arc4random_uniform(10);
    
    // 更新greenView的布局
    self.edgesConstraint.mas_equalTo(UIEdgeInsetsMake(20 * i, 20 * i, 20 * i, 20 * i));
}

效果如下:

另外膀哲,還可以通過將約束存儲(chǔ)在數(shù)組中來引用多個(gè)約束。

7.2 使用mas_updateConstraints方法更新約束十厢。

如果我們只需要更新約束的常量值等太,我們可以使用mas_updateConstraints方法來代替mas_makeConstraints方法。mas_updateConstraints對于更新一組約束很有用蛮放。

比如我們可以使用下面的代碼替換tap:方法中的內(nèi)容缩抡,實(shí)現(xiàn)之前的效果:

- (void)tap:(UITapGestureRecognizer *)tap
{
    int i = arc4random_uniform(10);
    
    // 使用mas_updateConstraints更新約束
    [self.greenView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20 * i, 20 * i, 20 * i, 20 * i));
    }];
}

7.3 使用mas_remakeConstraints方法更新約束。

mas_remakeConstraints類似于mas_updateConstraints,但它不是更新常量值瞻想,而是在再次安裝之前刪除所有約束压真。 這樣我們就可以提供不同的約束,而無需保留對要?jiǎng)h除約束的引用蘑险。

- (void)tap:(UITapGestureRecognizer *)tap
{
    int i = arc4random_uniform(10);
    
    // 使用remakeConstraints更新約束
    [self.greenView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20 * i, 20 * i, 20 * i, 20 * i));
    }];
}

7.4 總結(jié)

  • mas_makeConstraints只負(fù)責(zé)新增約束滴肿,每次調(diào)用會(huì)創(chuàng)建新的約束,如果對已存在的約束再次創(chuàng)建佃迄,會(huì)提示沖突(此時(shí)會(huì)存在對同一屬性的兩條約束)泼差。
  • mas_updateConstraints用于更新之前創(chuàng)建的約束,如果對已存在的約束進(jìn)行更新呵俏,沒有任何問題(此時(shí)只存在對同一屬性的最新一條約束)堆缘。
  • mas_remakeConstraints會(huì)清除之前的所有約束,僅保留最新的約束普碎。

8 使用Masonry定位發(fā)生沖突的約束

使用Masonry可以為視圖和約束創(chuàng)建有意義的名稱吼肥,這樣當(dāng)設(shè)置的約束發(fā)生沖突時(shí),我們可以定位到具體的元素麻车。

例如:如果我們使用下面的代碼為greenView添加布局:

[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20));
    make.height.lessThanOrEqualTo(@(200));
}];

運(yùn)行的時(shí)候控制臺(tái)會(huì)提示約束沖突:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
...... 
(
    "<MASLayoutConstraint:0x600000f01ce0 UIView:0x7fbdace024b0.top == UIView:0x7fbdace0b630.top + 20>",
    "<MASLayoutConstraint:0x600000f01da0 UIView:0x7fbdace024b0.bottom == UIView:0x7fbdace0b630.bottom - 20>",
    "<MASLayoutConstraint:0x600000f01e60 UIView:0x7fbdace024b0.height <= 200>",
    "<NSLayoutConstraint:0x600000818e10 UIView:0x7fbdace0b630.height == 736>"
)

Will attempt to recover by breaking constraint 
<MASLayoutConstraint:0x600000f01e60 UIView:0x7fbdace024b0.height <= 200>
......

面對這樣的輸出缀皱,我們很難找到造成約束沖突的問題。

Masonry為NSLayoutConstraint添加了一個(gè)分類动猬,重寫了- (NSString *)description方法的默認(rèn)實(shí)現(xiàn)啤斗。這樣我們就可以為視圖和約束提供有意義的名稱,并且還可以輕松選擇由Masonry創(chuàng)建的約束枣察。

更改上面的代碼如下:

self.greenView.mas_key = @"greenView";
self.view.mas_key = @"self.view";
//    MASAttachKeys(self.greenView, self.view);   // 也可以使用這種寫法自動(dòng)關(guān)聯(lián)一個(gè)key

// 添加布局
[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(20, 20, 20, 20)).key(@"edgesConstraint");
    make.height.lessThanOrEqualTo(@(200)).key(@"heightConstraint");
//        make.height.lessThanOrEqualTo(@(200)).key(@1234);    // key可以是任意值
}];

這次的運(yùn)行結(jié)果:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    ......
(
    "<MASLayoutConstraint:edgesConstraint[2] UIView:greenView.top == UIView:self.view.top + 20>",
    "<MASLayoutConstraint:edgesConstraint[3] UIView:greenView.bottom == UIView:self.view.bottom - 20>",
    "<MASLayoutConstraint:heightConstraint UIView:greenView.height <= 200>",
    "<NSLayoutConstraint:0x600002f9f6b0 UIView:self.view.height == 736>"
)

Will attempt to recover by breaking constraint 
<MASLayoutConstraint:heightConstraint UIView:greenView.height <= 200>
......

可以很明顯看到greenView設(shè)置的高度約束沖突了争占。

9 使用Masonry布局scrollView

對UIScrollView使用自動(dòng)布局的時(shí)候,經(jīng)常會(huì)遇到很多問題序目,比如布局無效,不能滑動(dòng)等伯襟。主要是因?yàn)閁IScrollView除了有自己的frame之外猿涨,還有一個(gè)contentSize。如果對子視圖進(jìn)行布局時(shí)參考了scrollView姆怪,例如設(shè)置子視圖的leading/trailing/top/bottom屬性等于scrollView的leading/trailing/top/bottom叛赚,這實(shí)際上是子視圖相對于scrollview的contentsize來確定的,而非bounds稽揭。而且由于scrollview的contentSize又是根據(jù)子視圖的位置決定的俺附,這樣就形成了一個(gè)依賴循環(huán)。

為了打破這種循環(huán)依賴溪掀,為ScrollView中的子視圖添加約束的時(shí)候需要注意:

  • 子視圖不能依賴任何scrollView有關(guān)的布局事镣,即不能參考scrollView的位置。
  • 子視圖除了要確定自己的大小以外揪胃,還需要確定自己與contentSize四周的距離璃哟,以此來確定contentSize氛琢。

比如我們現(xiàn)在有一個(gè)scrollView,將greenView作為子視圖添加到scrollView上随闪,代碼如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.view addSubview:self.scrollView];
    [self.scrollView addSubview:self.greenView];
    
    // 布局scrollView
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    // 布局greenView并確定scrollview的contentSize
    [self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
        // 1 確定contentSize的大小
        make.edges.equalTo(self.scrollView); 
        
        // 2 確定greenView的大小
        make.height.mas_equalTo(500);
        make.width.mas_equalTo(1000);
        // make.size.equalTo(self.scrollView).sizeOffset(CGSizeMake(500, -100));
    }];
}

上面代碼中我們使用make.edges.equalTo(self.scrollView);來確定contentSize的大小阳似,它表示greenView的上下左右距離contentSize的值為0,因此只要greenView的大小確定了铐伴,contentSize也就確定了撮奏。

如果要在scrollView上添加多個(gè)子視圖,可以將多個(gè)子視圖放入一個(gè)containerView中当宴,這樣布局子視圖時(shí)只需要參考containerView就可以了畜吊。

比如現(xiàn)在有一個(gè)scrollView,它里面有多個(gè)子視圖等間隔排列:


我們可以使用下面的代碼來實(shí)現(xiàn):

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.view addSubview:self.scrollView];
    [self.scrollView addSubview:self.containerView];

    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).inset(20);
    }];

    [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.scrollView);
        make.height.mas_equalTo(self.scrollView);
    }];
    
    // 添加子視圖
    int count = 10;
    UIView *previousView = nil;

    for (int i = 1; i <= count; ++i) {
        UIView *subView = [UIView new];
        subView.backgroundColor = [UIColor greenColor];
        subView.layer.borderColor = [UIColor blackColor].CGColor;
        subView.layer.borderWidth = 2.0;
        [self.containerView addSubview:subView];
        // 布局子視圖
        [subView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.bottom.equalTo(self.containerView);
            make.width.mas_equalTo(80);
            if (previousView) {
                make.left.equalTo(previousView.mas_right).offset(10);
            }
            else {
                make.left.equalTo(self.containerView).offset(10);
            }
        }];
        previousView = subView;
    }
    
    // 確定containerView的右邊界
    [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(previousView);
    }];
}

10 注意事項(xiàng)

  • 對視圖使用自動(dòng)布局之前即供,需要先將視圖添加到父視圖上定拟。
  • 使用Masonry時(shí)注意區(qū)分mas_equalToequalTo的區(qū)別:
    • mas_equalTo
      • 是對equalTo的封裝,支持NSNumber逗嫡、CGSize青自、CGPoint、UIEdgeInsets驱证;
      • mas_equalTo是一個(gè)Macro延窜,比較的是值;
      • 一般對于數(shù)值元素使用mas_equalTo抹锄,例如make.width.mas_equalTo(100);逆瑞。
    • equalTo
      • 只支持基本類型;
      • equalTo比較的是view伙单;
      • 對于對象或多個(gè)屬性的處理使用equalTo获高,例如make.left.and.right.equalTo(self.view);
  • 對視圖使用自動(dòng)布局后吻育,如果嘗試獲取它的frame很可能獲取到的是0念秧。對于這種情況,我們可以在獲取視圖frame之前手動(dòng)調(diào)用layoutIfNeeded方法來更新布局布疼。
  • Masonry中的block不存在循環(huán)引用的問題摊趾,不必使用weakSelf。雖然block內(nèi)引用了view游两,但block并沒有被view所持有砾层,因此不會(huì)發(fā)生循環(huán)引用。

11 參考資料

Masonry
Masonry介紹與使用實(shí)踐(快速上手Autolayout)
Masonry 簡單使用
iOS開發(fā)之Masonry框架-使用方法須知
ScrollView使用Masonry自動(dòng)布局
史上最簡單的UIScrollView+Autolayout出坑指南
iOS開發(fā)筆記 | 由使用Masonry布局不能立即獲取到frame想到的一些問題
Masonry布局控件frame為0的問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贱案,一起剝皮案震驚了整個(gè)濱河市肛炮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖铸董,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祟印,死亡現(xiàn)場離奇詭異,居然都是意外死亡粟害,警方通過查閱死者的電腦和手機(jī)蕴忆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悲幅,“玉大人套鹅,你說我怎么就攤上這事√撸” “怎么了卓鹿?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長留荔。 經(jīng)常有香客問我吟孙,道長,這世上最難降的妖魔是什么聚蝶? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任杰妓,我火速辦了婚禮,結(jié)果婚禮上碘勉,老公的妹妹穿的比我還像新娘巷挥。我一直安慰自己,他們只是感情好验靡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布倍宾。 她就那樣靜靜地躺著,像睡著了一般胜嗓。 火紅的嫁衣襯著肌膚如雪高职。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天辞州,我揣著相機(jī)與錄音初厚,去河邊找鬼。 笑死孙技,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的排作。 我是一名探鬼主播牵啦,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妄痪!你這毒婦竟也來了哈雏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎裳瘪,沒想到半個(gè)月后土浸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彭羹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年黄伊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片派殷。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡还最,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毡惜,到底是詐尸還是另有隱情拓轻,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布经伙,位于F島的核電站扶叉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏帕膜。R本人自食惡果不足惜枣氧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泳叠。 院中可真熱鬧作瞄,春花似錦、人聲如沸危纫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丹喻,卻和暖如春犀盟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搪桂。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盯滚,地道東北人踢械。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像魄藕,于是被迫代替她去往敵國和親内列。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容