Masonry官方使用教程翻譯

以前一直用frame佈局,如今改用自動佈局,Masonry是主流框架,對於有AutoLayout基礎的人比較容易上手,閒來翻譯了一下官方博客,把Demo的例子每一個研究了下,發現確實挺好用的,就簡單記錄下吧git

Masonry仍舊在持續維護中,藉助於開放社區,咱們致力於修復漏洞和合並優秀的需求。然而你的項目是用Swift語言的,咱們推薦使用SnapKit,由於它有着更簡短的API來更好適應Swift.
Masonry是一種輕量級的佈局框架,採用了更良好的語言來封裝AutoLayout。Masonry有本身的佈局DSL,提供了一種鏈式方式來描述你的NSLayoutConstraints,經過這種方式產生的佈局代碼更簡潔,更易讀。Masonry支持iOS和Mac OS X.
 
NSLayoutConstraints的弊端在哪?
經過底層的AutoLayout能夠比較有效和靈活的組織和佈局你的Views,然而經過代碼建立約束比較冗長且不生動。試想這樣一個例子:建立一個View距離父視圖的邊界都爲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],

 ]];
 
像這種簡單的例子代碼都如此冗長,當你的視圖複雜的時候可讀性就更差了。另一種方式可使用VFL,代碼更少點,不過這種ASCII風格的語言有它本身的弊端而且實現動畫效果比較難,就好比NSLayoutConstraint constraintsWithVisualFormat:返回一個數組。
認識下MASConstraintMaker
一樣的例子咱們使用MASConstraintMaker來編寫
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會自動給最合適的視圖添加約束的,而且也默認設置了view1.translatesAutoresizingMaskIntoConstraints = NO
 
不是全部的約束都是equal
.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
二者效果等價
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);
 
3. NSNumber
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)
 
AutoLayout 能夠容許寬度和高度設置爲常量,可是像left、right、CenterX這些屬性是不容許賦予常量的,當你賦予一個常量的時候至關於和它的父視圖作對比,好比:
//creates view.left = view.superview.left + 10
make.left.lessThanOrEqualTo(@10)
 
固然,若是你不想對數字進行裝箱,可使用前綴mas_,這個會自動幫你裝箱,若是你不想加這個前綴,能夠在導入Masonry前定義一個宏MAS_SHORTHAND_GLOBALS。
 
4. NSArray
包含各類類型的數組
make.height.equalTo(@[view1.mas_height, view2.mas_height]);
make.height.equalTo(@[view1, view2]);
make.left.equalTo(@[view1, @100, view3.right]);
 
學會使用優先級
 
.priority 容許你使用指定的優先級
 
.priorityHigh 至關於 UILayoutPriorityDefaultHigh
 
.priorityMedium 介於高優先級和低優先級之間
 
.priorityLow 至關於 UILayoutPriorityDefaultLow
 
優先級通常放在鏈式語法的最後,就像這樣
make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();

make.top.equalTo(label.mas_top).with.priority(600);
 
組合,組合,組合
Masonry提供了一些便捷的方式能夠在同一時間建立多個約束,這些稱爲MASCompositeConstraints
edges(邊距)
// 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);
 
增長更好的體驗
有時候你須要修改約束爲了達到動畫效果或者移除/更新約束。Masonry提供了多種不一樣方法更新約束
 
1. References
你可使用屬性或者成員變量來持有一個特定的約束,或者使用數組來持有多個約束
// 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 (更新約束)
若是你只是想更新約束的常量值,你可使用mas_updateConstraints來代替mas_makeConstraints
// this is Apple's recommended place for adding/updating constraints
// this method can get called multiple times in response to setNeedsUpdateConstraints
// which can be called by UIKit internally or in your code if you need to trigger an update to your constraints
- (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,它會刪除掉以前全部建立的約束,這個會產生一些新的約束,這樣你能夠不用持有那些你須要刪除的約束。
- (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);
        }
    }];
}
你能夠在官方Demo中看到更多的關於這三種方式的使用。
 
使用中可能遇到的問題
佈局視圖並不必定都會出現預期效果,當發現錯誤崩潰的時候,你確定不想看到控制檯輸出如下語句:
 
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,你能夠給視圖和約束起一個有意義的名稱,並且能夠很容易找出那些約束,因此錯誤時你的控制檯就會輸出這樣清晰報錯信息:
Unable to simultaneously satisfy constraints......blah blah blah....
(
    "<NSAutoresizingMaskLayoutConstraint:0x8887740 MASExampleDebuggingView:superview.height == 416>",
    "<MASLayoutConstraint:ConstantConstraint UILabel:messageLabel.height >= 5000>",
    "<MASLayoutConstraint:BottomConstraint UILabel:messageLabel.bottom == MASExampleDebuggingView:superview.bottom - 10>",
    "<MASLayoutConstraint:ConflictingConstraint[0] UILabel:messageLabel.top == MASExampleDebuggingView:superview.top + 1>"
)

Will attempt to recover by breaking constraint
<MASLayoutConstraint:ConstantConstraint UILabel:messageLabel.height >= 5000>
在官方Demo有專門調試的例子介紹
 
 
那麼我應該在哪裏建立個人約束呢
蘋果的推薦作法以下:
@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];
}
相關文章
相關標籤/搜索