Masonry詳解

Masonry GitHub地址

** Masonry仍然在積極維護踏枣,但是如果您在的項目中使用Swift,我們建議使用SnapKit,因為它可以通過更簡單的API钙蒙,提供更好的類型安全性茵瀑。**

Masonry是一個輕量級的布局框架,它將AutoLayout與更好的語法相結合躬厌。Masonry有自己的布局DSL马昨,它提供了一種可鏈接的方式來描述您的NSLayoutConstraints,從而導致更簡潔和可讀性的布局代碼扛施。Masonry支持iOS和Mac OS X.

例如鸿捧,請查看Masonry工作空間中的Masonry iOS Examples項目。pod install下載后需要運行疙渣。

NSLayoutConstraints有什么問題匙奴?

自動布局是組織和布置您的視圖的強大而靈活的方式。然而從代碼創(chuàng)建約束是冗長而不是很描述性的妄荔。想象一下泼菌,一個簡單的例子谍肤,你想要有一個視圖填充其超級視圖,視圖距離其父視圖的每個邊界都是10像素哗伯。

UIView *superview = self.view;

UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[superview addConstraints:@[

    //view1 constraints
    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeTop
                                multiplier:1.0
                                  constant:padding.top],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeLeft
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeLeft
                                multiplier:1.0
                                  constant:padding.left],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeBottom
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeBottom
                                multiplier:1.0
                                  constant:-padding.bottom],

    [NSLayoutConstraint constraintWithItem:view1
                                 attribute:NSLayoutAttributeRight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:superview
                                 attribute:NSLayoutAttributeRight
                                multiplier:1
                                  constant:-padding.right],

 ]];

即使有這樣一個簡單的例子荒揣,當你有超過2或3個視圖時,所需的代碼是相當冗長的焊刹,并且很快變得不可讀系任。另一個選擇是使用視覺格式語言(VFL),這是一個不那么長的時間虐块。然而俩滥,ASCII類型的語法有自己的陷阱,它也有點難以動畫贺奠,因為NSLayoutConstraint constraintsWithVisualFormat:返回一個數組举农。

準備好迎接你的上帝!

使用MASConstraintMaker創(chuàng)建的相同約束

UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
    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);
}];

另外請注意敞嗡,在第一個例子中,我們必須添加約束到超級視圖[superview addConstraints:...航背。然而喉悴,Masonry會自動地添加約束到適當的視圖。Masonry 會為你自動調用view1.translatesAutoresizingMaskIntoConstraints = NO;

并不是所有的東西都是平等的

.equalTo相當于NSLayoutRelationEqual
.lessThanOrEqualTo相當于NSLayoutRelationLessThanOrEqual
.greaterThanOrEqualTo相當于NSLayoutRelationGreaterThanOrEqual

這三個等式約束接受一個參數玖媚,可以是以下任何一個:

1箕肃、MASViewAttribute

make.centerX.lessThanOrEqualTo(view2.mas_left)

MASViewAttribute NSLayoutAttribute
view.mas_left NSLayoutAttributeLeft
view.mas_right NSLayoutAttributeRight
view.mas_top NSLayoutAttributeTop
view.mas_bottom NSLayoutAttributeBottom
view.mas_leading NSLayoutAttributeLeading
view.mas_trailing NSLayoutAttributeTrailing
view.mas_width NSLayoutAttributeWidth
view.mas_height NSLayoutAttributeHeight
view.mas_centerX NSLayoutAttributeCenterX
view.mas_centerY NSLayoutAttributeCenterY
view.mas_baseline NSLayoutAttributeBaseline

2、 UIView / NSView

如果你想要view.left大于或等于label.left:

//這兩個約束完全一樣
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);

3今魔、NSNumber

自動布局允許將寬度和高度設置為常量值勺像。如果要將視圖設置為具有最小和最大寬度,則可以將數字傳遞給相等塊:

// width> = 200 && width <= 400 
make.width.greaterThanOrEqualTo(@ 200);
make.width.lessThanOrEqualTo(@ 400)

但是自動布局不允許將對齊屬性(例如left错森,right吟宦,centerY等)設置為常量值。所以如果你傳遞這些屬性的NSNumber涩维,那么Masonry會把它們變成相對于view的superview的約束殃姓,即:

//創(chuàng)建view.left = view.superview.left + 10 
make.left.lessThanOrEqualTo(@ 10)

您可以使用基本數據類型和結構體來構建約束,而不是使用NSNumber瓦阐,如下所示:

make.top.mas_equalTo(42);
make.height.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(50, 100));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 0, 10, 0));
make.left.mas_equalTo(view).mas_offset(UIEdgeInsetsMake(10, 0, 10, 0));

默認情況下蜗侈,支持自動封裝的宏是前綴mas_。MAS_SHORTHAND_GLOBALS在導入Masonry之前定義睡蟋,可以使用未加上的版本踏幻。

4、NSArray

任何先前類型的混合數組


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

學習優(yōu)先級

.priority 允許您指定確切的優(yōu)先級
.priorityHigh相當于UILayoutPriorityDefaultHigh
.priorityMedium是高低之間的一半
.priorityLow相當于UILayoutPriorityDefaultLow

優(yōu)先級可以在如下所示的約束鏈的末尾加以解決:

make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();

make.top.equalTo(label.mas_top).with.priority(600);

組合

Masonry還給你一些方便的方法戳杀,同時創(chuàng)造多個約束该面。這些稱為MASCompositeConstraints夭苗。

邊緣

// make top, left, bottom, right equal view2
make.edges.equalTo(view2);

// make top = superview.top + 5, left = superview.left + 10,
//      bottom = superview.bottom - 15, right = superview.right - 20
make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20))

size

// make width and height greater than or equal to titleLabel
make.size.greaterThanOrEqualTo(titleLabel)

// make width = superview.width + 100, height = superview.height - 50
make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))

center

// make centerX and centerY = button1
make.center.equalTo(button1)

// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))

您可以鏈接視圖屬性以提高可讀性:

// All edges but the top should equal those of the superview
make.left.right.and.bottom.equalTo(superview);
make.top.equalTo(otherView);

Hold on for dear life

有時您需要修改現有約束以便動畫或刪除/替換約束。在Masonry中吆倦,有幾種不同的更新約束方法听诸。

1、References

您可以通過將約束make表達式的結果分配給局部變量或類屬性來保持特定約束的引用蚕泽。您還可以通過將它們存儲在數組中來引用多個約束晌梨。

// in public/private interface
@property (nonatomic, strong) MASConstraint *topConstraint;

...

// when making constraints
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    self.topConstraint = make.top.equalTo(superview.mas_top).with.offset(padding.top);
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
}];

...
// then later you can call
[self.topConstraint uninstall];

2翘簇、mas_updateConstraints

或者博秫,如果您只更新約束的常量值,則可以使用convience方法mas_updateConstraints而不是mas_makeConstraints

//這是蘋果推薦添加/更新約束的地方
//調用`setNeedsUpdateConstraints `時思恐,這個方法可以得到多次調用
//如果你需要觸發(fā)更新了自己的約束荒吏,可以通過UIKit的內部或在你的代碼使用
- (void)updateConstraints {
    [self.growingButton mas_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];
}

3敛惊、mas_remakeConstraints

mas_updateConstraints對于更新一組約束是有用的,但是除了更新常量值之外,之前的約束都會被清除绰更。

mas_remakeConstraints類似于mas_updateConstraints但不是更新常量值瞧挤,它將在重新安裝之前刪除所有約束。這可以讓您提供不同的約束儡湾,而無需保留對要刪除的引用特恬。

- (void)changeButtonPosition {
    [self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(self.buttonSize);

        if (topLeft) {
            make.top.and.left.offset(10);
        } else {
            make.bottom.and.right.offset(-10);
        }
    }];
}

您可以在Masonry iOS示例項目中找到更詳細的三種方法的例子。

When the ^&*!@ hits the fan!

約束并不是都很順利徐钠。所以當控制臺有這樣的輸出:

Unable to simultaneously satisfy constraints.....blah blah blah....
(
    "<NSLayoutConstraint:0x7189ac0 V:[UILabel:0x7186980(>=5000)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x839ea20 h=--& v=--& V:[MASExampleDebuggingView:0x7186560(416)]>",
    "<NSLayoutConstraint:0x7189c70 UILabel:0x7186980.bottom == MASExampleDebuggingView:0x7186560.bottom - 10>",
    "<NSLayoutConstraint:0x7189560 V:|-(1)-[UILabel:0x7186980]   (Names: '|':MASExampleDebuggingView:0x7186560 )>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7189ac0 V:[UILabel:0x7186980(>=5000)]>

Masonry為NSLayoutConstraint添加了一個類別癌刽,它覆蓋了默認的實現- (NSString *)description。現在尝丐,您可以給觀點和約束提供有意義的名稱显拜,并且還可以輕松地挑選出由Masonry創(chuàng)建的約束。

有關如何設置此項的示例爹袁,請查看Masonry工作空間中的Masonry iOS示例項目远荠。

我應該在哪里創(chuàng)建我的約束?

@implementation DIYCustomView

- (id)init {
    self = [super init];
    if (!self) return nil;

    // --- Create your views here ---
    self.button = [[UIButton alloc] init];

    return self;
}

// tell UIKit that you are using AutoLayout
+ (BOOL)requiresConstraintBasedLayout {
    return YES;
}

// this is Apple's recommended place for adding/updating constraints
- (void)updateConstraints {

    // --- remake/update constraints here
    [self.button remakeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(@(self.buttonSize.width));
        make.height.equalTo(@(self.buttonSize.height));
    }];
    
    //according to apple super should be called at end of method
    [super updateConstraints];
}

- (void)didTapButton:(UIButton *)button {
    // --- Do your changes ie change variables that affect your layout etc ---
    self.buttonSize = CGSize(200, 200);

    // tell constraints they need updating
    [self setNeedsUpdateConstraints];
}

@end

Installation

使用

orosome CocoaPods失息。

在你的Podfile中

pod 'Masonry'

如果你想使用沒有所有那些麻煩的'mas_'前綴的masonry矮台。在導入masonry之前,將#define MAS_SHORTHAND添加到您的prefix.pch中

define MAS_SHORTHAND

引入頭文件

import "Masonry.h"

代碼片段

將包含的代碼片段復制為

`~/Library/Developer/Xcode/UserData/CodeSnippets`
以閃電般的速度編寫您的Masonry根时!

mas_make -> [<view> mas_makeConstraints:^(MASConstraintMaker *make){<code>}];

mas_update-> [<view> mas_updateConstraints:^(MASConstraintMaker *make){<code>}];

mas_remake -> [<view> mas_remakeConstraints:^(MASConstraintMaker *make){<code>}];

特征

  • 不限于自動布局的子集瘦赫。
    任何NSLayoutConstraint都可以做,Masonry也可以做蛤迎!

  • 很好的調試支持确虱,給你的意見和約束有意義的名字。

  • 約束看起來像句子替裆。

  • 沒有瘋狂的宏觀魔法校辩。
    Maonry不會用宏污染全局命名空間窘问。

  • 不是字符串或字典,因此您可以編譯時間檢查宜咒。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末惠赫,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子故黑,更是在濱河造成了極大的恐慌儿咱,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件场晶,死亡現場離奇詭異混埠,居然都是意外死亡,警方通過查閱死者的電腦和手機诗轻,發(fā)現死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門钳宪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扳炬,你說我怎么就攤上這事吏颖。” “怎么了恨樟?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵半醉,是天一觀的道長。 經常有香客問我厌杜,道長,這世上最難降的妖魔是什么计螺? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任夯尽,我火速辦了婚禮,結果婚禮上登馒,老公的妹妹穿的比我還像新娘匙握。我一直安慰自己,他們只是感情好陈轿,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布圈纺。 她就那樣靜靜地躺著,像睡著了一般麦射。 火紅的嫁衣襯著肌膚如雪蛾娶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天潜秋,我揣著相機與錄音蛔琅,去河邊找鬼。 笑死峻呛,一個胖子當著我的面吹牛罗售,可吹牛的內容都是我干的辜窑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼寨躁,長吁一口氣:“原來是場噩夢啊……” “哼穆碎!你這毒婦竟也來了?” 一聲冷哼從身側響起职恳,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤所禀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后话肖,有當地人在樹林里發(fā)現了一具尸體北秽,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年最筒,在試婚紗的時候發(fā)現自己被綠了贺氓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡床蜘,死狀恐怖辙培,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情邢锯,我是刑警寧澤扬蕊,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站丹擎,受9級特大地震影響尾抑,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蒂培,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一再愈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧护戳,春花似錦翎冲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钳枕,卻和暖如春缴渊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鱼炒。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工疟暖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓俐巴,卻偏偏與公主長得像骨望,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子欣舵,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容