系列:iOS開發(fā)-Masonry的使用

系列:iOS開發(fā)-Masonry的使用

對(duì)于一個(gè)開發(fā)者來說,我們是肯定需要和布局打交道的,最早的我們可能會(huì)使用手寫frame或者bounce等,在之后我們可能會(huì)方便的使用xib或者storyboard來拉約束等.
我們會(huì)發(fā)現(xiàn)使用約束,autolayout是很方便的方法,但是僅限于在xib或者storyboard中拉出來的約束,如果我們是手寫的話,你會(huì)發(fā)現(xiàn)實(shí)在過于的繁瑣和啰嗦.

于是就出現(xiàn)了Masonry,這個(gè)高效的三方框架
Masonry是一個(gè)輕量級(jí)的布局框架 擁有自己的描述語法 采用更優(yōu)雅的鏈?zhǔn)秸Z法封裝自動(dòng)布局 簡潔明了 并具有高可讀性 而且同時(shí)支持 iOS 和 Max OS X权旷。
至于學(xué)習(xí)的話,最有效的方式就是下載官方的demo來學(xué)習(xí).這里我也就不寫自己的demo來班門弄斧了.

Masonry 源碼:https://github.com/Masonry/Masonry

下載下來
雙擊打開工程


這里寫圖片描述

選擇iOS Examples,至于設(shè)備的話,選擇自己習(xí)慣的就好


這里寫圖片描述

運(yùn)行之后我們能看到一個(gè)完整的列表
這里寫圖片描述

我們一個(gè)一個(gè)學(xué)習(xí),首先是Basic的內(nèi)容,我們觀察界面,同時(shí)進(jìn)入代碼中閱讀代碼
這里寫圖片描述

我們可以看到上面兩個(gè)view,一個(gè)綠色一個(gè)紅色,下面有一個(gè)藍(lán)色的view,很簡單的布局,我們?nèi)绻褂脁ib等拉的話很好拉,弄幾個(gè)帶有比例的約束就好了,
我們看看Masonry的實(shí)現(xiàn),首先它沒有xib,另外它使用的不是frame.手寫的代碼,我們知道他就是手寫的約束.我們看看內(nèi)容

int padding = 10;

//if you want to use Masonry without the mas_ prefix
    //define MAS_SHORTHAND before importing Masonry.h see Masonry iOS Examples-Prefix.pch
    [greenView makeConstraints:^(MASConstraintMaker *make) {
        make.top.greaterThanOrEqualTo(superview.top).offset(padding);
        make.left.equalTo(superview.left).offset(padding);
        make.bottom.equalTo(blueView.top).offset(-padding);
        make.right.equalTo(redView.left).offset(-padding);
        make.width.equalTo(redView.width);

        make.height.equalTo(redView.height);
        make.height.equalTo(blueView.height);
        
    }];

閱讀這一段,首先有一段注釋,如果想要使用不帶有mas_top的而是簡寫成top的,在pch文件中添加一段宏定義,這里我們看看就好了


這里寫圖片描述

下面是代碼,
約束代碼我們可以看到是封裝在一個(gè)block中,使用的是makeConstraints的方法.
在Masonry中有三種創(chuàng)建約束的方法

makeConstraints 這個(gè)方法只會(huì)添加新的約束
mas_updateConstraints 這個(gè)方法將會(huì)覆蓋以前的某些特定的約束
mas_remakeConstraints 這個(gè)方法會(huì)將以前的約束全部刪除蕉世,添加新的約束
/*
mas_makeConstraints 只負(fù)責(zé)新增約束 Autolayout不能同時(shí)存在兩條針對(duì)于同一對(duì)象的約束 否則會(huì)報(bào)錯(cuò)
mas_updateConstraints 針對(duì)上面的情況 會(huì)更新在block中出現(xiàn)的約束 不會(huì)導(dǎo)致出現(xiàn)兩個(gè)相同約束的情況
mas_remakeConstraints 則會(huì)清除之前的所有約束 僅保留最新的約束
三種函數(shù)善加利用 就可以應(yīng)對(duì)各種情況了
*/

內(nèi)容很簡單,跟我們xib拉約束的方式是基本完全一樣的
讀起來也很簡單,make.left.equalTo(superview.left).offset(padding);
讓左邊等于父視圖的左邊偏移10個(gè)像素單位
make.bottom.equalTo(blueView.top).offset(-padding);
讓底部等于藍(lán)色視圖的頂部偏移-10個(gè)像素

我們點(diǎn)擊top或者其他跳轉(zhuǎn)到Masonry中看看支持哪些屬性

@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

跟我們的約束一樣,上下左右寬高,中心點(diǎn)等,
所以對(duì)于一般的約束,我們至此都已經(jīng)可以完全自定義了
當(dāng)然我們也可以注意一下這個(gè)


這里寫圖片描述

至于干什么也不用解釋,就是可以同時(shí)添加多個(gè)約束

接下來在看列表的下一項(xiàng)MASExampleUpdateView


這里寫圖片描述
+ (BOOL)requiresConstraintBasedLayout
{
    return YES;
}

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

    [self.growingButton 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];
}

- (void)didTapGrowButton:(UIButton *)button {
    self.buttonSize = CGSizeMake(self.buttonSize.width * 1.3, self.buttonSize.height * 1.3);

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

    // update constraints now so we can animate the change
    [self updateConstraintsIfNeeded];

    [UIView animateWithDuration:0.4 animations:^{
        [self layoutIfNeeded];
    }];
}

首先是requiresConstraintBasedLayout
介紹是這樣的
constraint-based layout engages lazily when someone tries to use it (e.g., adds a constraint to a view). If you do all of your constraint set up in -updateConstraints, you might never even receive updateConstraints if no one makes a constraint. To fix this chicken and egg problem, override this method to return YES if your view needs the window to use constraint-based layout.
意思就是基于約束的布局是懶觸發(fā)的茴厉,只有在添加了約束的情況下品擎,系統(tǒng)才會(huì)自動(dòng)調(diào)用 -updateConstraints 方法,如果把所有的約束放在 updateConstraints中谅摄,那么系統(tǒng)將會(huì)不知道你的布局方式是基于約束的,所以 重寫+requiresConstraintBasedLayout 返回YES就是明確告訴系統(tǒng):雖然我之前沒有添加約束,但我確實(shí)是基于約束的布局沛厨!這樣可以保證系統(tǒng)一定會(huì)調(diào)用 -updateConstraints 方法 從而正確添加約束.

我們可以看到這一次Masonry的約束是寫在updateConstraints中的.
這只是一個(gè)小的知識(shí)點(diǎn).
接下來是更新的方式,只要的代碼是這幾個(gè)

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

    // update constraints now so we can animate the change
    [self updateConstraintsIfNeeded];

    [UIView animateWithDuration:0.4 animations:^{
        [self layoutIfNeeded];
    }];

使用上面的方式來更新約束,這樣系統(tǒng)就會(huì)再次調(diào)用updateConstraints來實(shí)現(xiàn)約束的更新,從而實(shí)現(xiàn)動(dòng)畫,我們可以點(diǎn)擊按鈕來觀看效果,按鈕點(diǎn)擊一次變大一次,寬高是之前的1.3倍

[self.growingButton 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);
    }];

另外這里涉及到優(yōu)先級(jí)的部分,首先是中心點(diǎn)位置跟父視圖的中心點(diǎn)一致,其次是寬高優(yōu)先的是小于<=父視圖的寬高,在滿足的情況下在是等于指定寬高
在這個(gè)demo中我們可以在學(xué)習(xí)一下優(yōu)先級(jí)的調(diào)用和更新約束的邏輯

接下來是MASExampleRemakeView
在這里我就不介紹了
使用的更新約束的方法為

[self.movingButton remakeConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(@(100));
        make.height.equalTo(@(100));
        
        if (self.topLeft) {
            make.left.equalTo(self.left).with.offset(10);
            make.top.equalTo(self.top).with.offset(10);
        }
        else {
            make.bottom.equalTo(self.bottom).with.offset(-10);
            make.right.equalTo(self.right).with.offset(-10);
        }
    }];

大意是移除之前的約束,添加新的約束,也是在updateConstraints方法中實(shí)現(xiàn)

再繼續(xù) MASExampleSidesView
我們看到好多的view,眼睛都花掉了,這個(gè)肯定要寫很久吧


這里寫圖片描述

好吧,我錯(cuò)了實(shí)現(xiàn)的方法就幾行而已

UIView *lastView = self;
    for (int i = 0; i < 10; i++) {
        UIView *view = UIView.new;
        view.backgroundColor = [self randomColor];
        view.layer.borderColor = UIColor.blackColor.CGColor;
        view.layer.borderWidth = 2;
        [self addSubview:view];
        
        [view mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(lastView).insets(UIEdgeInsetsMake(5, 10, 15, 20));
        }];
        
        lastView = view;
    }

一個(gè)循環(huán)創(chuàng)建,在這里我們可以看到一個(gè)新的關(guān)鍵字edges 是的,這是一個(gè)新的關(guān)鍵字,表示了整個(gè)邊緣,不需要重復(fù)寫上下左右
我們進(jìn)入類中可以看到

- (MASConstraint *)edges {
    return [self addConstraintWithAttributes:MASAttributeTop | MASAttributeLeft | MASAttributeRight | MASAttributeBottom];
}

- (MASConstraint *)size {
    return [self addConstraintWithAttributes:MASAttributeWidth | MASAttributeHeight];
}

- (MASConstraint *)center {
    return [self addConstraintWithAttributes:MASAttributeCenterX | MASAttributeCenterY];
}

他幫助你實(shí)現(xiàn)了邊緣 大小 中心 三種方法,所以之前的base的方式我們也可以嘗試著簡寫看看..
然后是insets 我們看到的是類似collectionView的組的間距,距離上下左右的像素差距,我們很容易理解

- (MASConstraint * (^)(MASEdgeInsets))insets {
    return ^id(MASEdgeInsets insets){
        self.insets = insets;
        return self;
    };
}

- (MASConstraint * (^)(CGFloat))inset {
    return ^id(CGFloat inset){
        self.inset = inset;
        return self;
    };
}

- (MASConstraint * (^)(CGSize))sizeOffset {
    return ^id(CGSize offset) {
        self.sizeOffset = offset;
        return self;
    };
}

- (MASConstraint * (^)(CGPoint))centerOffset {
    return ^id(CGPoint offset) {
        self.centerOffset = offset;
        return self;
    };
}

- (MASConstraint * (^)(CGFloat))offset {
    return ^id(CGFloat offset){
        self.offset = offset;
        return self;
    };
}

- (MASConstraint * (^)(NSValue *value))valueOffset {
    return ^id(NSValue *offset) {
        NSAssert([offset isKindOfClass:NSValue.class], @"expected an NSValue offset, got: %@", offset);
        [self setLayoutConstantWithValue:offset];
        return self;
    };
}

除此以外,其實(shí)現(xiàn)了insets\inset\sizeOffset\centerOffset\offset.等方法我們可以注意到這些都是Modifies the NSLayoutConstraint constant,意思是修改約束,我們可以看到都是添加一些在固定了大小之后的微調(diào)的方式...我們合理運(yùn)用的時(shí)候會(huì)很方便

接下來就稍微有點(diǎn)復(fù)雜了,我們看看MASExampleAspectFitView
demo首先創(chuàng)建了4個(gè)視圖

// Create views
        self.topView = [[UIView alloc] initWithFrame:CGRectZero];
        self.topInnerView = [[UIView alloc] initWithFrame:CGRectZero];
        self.bottomView = [[UIView alloc] initWithFrame:CGRectZero];
        self.bottomInnerView = [[UIView alloc] initWithFrame:CGRectZero];
        
        // Set background colors
        UIColor *blueColor = [UIColor colorWithRed:0.663 green:0.796 blue:0.996 alpha:1];
        [self.topView setBackgroundColor:blueColor];

        UIColor *lightGreenColor = [UIColor colorWithRed:0.784 green:0.992 blue:0.851 alpha:1];
        [self.topInnerView setBackgroundColor:lightGreenColor];

        UIColor *pinkColor = [UIColor colorWithRed:0.992 green:0.804 blue:0.941 alpha:1];
        [self.bottomView setBackgroundColor:pinkColor];
        
        UIColor *darkGreenColor = [UIColor colorWithRed:0.443 green:0.780 blue:0.337 alpha:1];
        [self.bottomInnerView setBackgroundColor:darkGreenColor];

這里不是我們需要關(guān)注的,我們看約束
先看上面兩個(gè)

// Layout top and bottom views to each take up half of the window
        [self addSubview:self.topView];
        [self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.right.and.top.equalTo(self);
        }];
        
        [self addSubview:self.bottomView];
        [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.right.and.bottom.equalTo(self);
            make.top.equalTo(self.topView.mas_bottom);
            make.height.equalTo(self.topView);
        }];

這里我們看到了鏈?zhǔn)骄幊趟枷氲膶?shí)現(xiàn)將多個(gè)操作通過.連接在一起成為一句代碼make.left.right.and.top.equalTo(self);
讓,左右和上都與父視圖一致,至于鏈?zhǔn)骄幊趟枷?后續(xù)會(huì)介紹,這里就先不說了,大意是其不需要考慮調(diào)用順序,只需要知道考慮結(jié)果摔认,類似于蝴蝶效應(yīng)逆皮,產(chǎn)生一個(gè)事件,會(huì)影響很多東西参袱,這些事件像流一樣的傳播出去电谣,然后影響結(jié)果,借用面向?qū)ο蟮囊痪湓捘ㄊ矗f物皆是流剿牺。
上面的約束是固定了左右上 下面的約束是固定了左右下 ,然后讓下面的頂部跟上面的底部一樣 且兩個(gè)高度一樣,這樣我們就能看到了這樣的效果

這里寫圖片描述

繼續(xù)看下一個(gè)約束

[self.topView addSubview:self.topInnerView];
        [self.topInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.equalTo(self.topInnerView.mas_height).multipliedBy(3);
            
            make.width.and.height.lessThanOrEqualTo(self.topView);
            make.width.and.height.equalTo(self.topView).with.priorityLow();
            
            make.center.equalTo(self.topView);
        }];

寬度是高度的3倍,這里我們又看到了新的約束方式,比例multipliedBy(3)
我們還看到了and 當(dāng)然,其沒有任何作用,僅僅是為了讀寫順暢
設(shè)置了寬度和高度的大小為小于或者等于父視圖的寬高,中心點(diǎn)的位置,確定了其是一個(gè)在父視圖中心的一個(gè)和父視圖等寬的高度是寬度1/3的一個(gè)位置和大小的視圖
至于后面的另外的一個(gè)約束就不做說明了
補(bǔ)充一句

multipler屬性表示約束值為約束對(duì)象的乘因數(shù), dividedBy屬性表示約束值為約束對(duì)象的除因數(shù)

例如我們可以寫成make.height.equalTo(self.topInnerView.mas_width).dividedBy(3); 也是一樣的效果

接下來就是基于動(dòng)畫的約束了MASExampleAnimatedView

首先是跟Base一樣的三個(gè)view的約束,只是換一個(gè)方式

UIView *superview = self;
    int padding = self.padding = 10;
    UIEdgeInsets paddingInsets = UIEdgeInsetsMake(self.padding, self.padding, self.padding, self.padding);

    self.animatableConstraints = NSMutableArray.new;

    [greenView mas_makeConstraints:^(MASConstraintMaker *make) {
        [self.animatableConstraints addObjectsFromArray:@[
            make.edges.equalTo(superview).insets(paddingInsets).priorityLow(),
            make.bottom.equalTo(blueView.mas_top).offset(-padding),
        ]];

        make.size.equalTo(redView);
        make.height.equalTo(blueView.mas_height);
    }];

    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        [self.animatableConstraints addObjectsFromArray:@[
            make.edges.equalTo(superview).insets(paddingInsets).priorityLow(),
            make.left.equalTo(greenView.mas_right).offset(padding),
            make.bottom.equalTo(blueView.mas_top).offset(-padding),
        ]];

        make.size.equalTo(greenView);
        make.height.equalTo(blueView.mas_height);
    }];

    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        [self.animatableConstraints addObjectsFromArray:@[
            make.edges.equalTo(superview).insets(paddingInsets).priorityLow(),
        ]];

        make.height.equalTo(greenView.mas_height);
        make.height.equalTo(redView.mas_height);
    }];

優(yōu)先級(jí)底的我們最后看,首先是確定了各個(gè)view的位置關(guān)系,綠色下邊是藍(lán)色,紅色左邊是綠色,下邊是藍(lán)色,且三個(gè)等高,然后再分別看優(yōu)先級(jí)低的約束進(jìn)行補(bǔ)充,都是距離父視圖相同的間距,這樣我們就能夠想象出它的界面約束的關(guān)系形成的效果


這里寫圖片描述

很顯然,這種布局方式比base又高級(jí)了一點(diǎn).值得學(xué)習(xí)
然后我們看到,其會(huì)將某些約束關(guān)系添加到數(shù)組中保存起來,
然后

int padding = invertedInsets ? 100 : self.padding;
    UIEdgeInsets paddingInsets = UIEdgeInsetsMake(padding, padding, padding, padding);
    for (MASConstraint *constraint in self.animatableConstraints) {
        constraint.insets = paddingInsets;
    }

    [UIView animateWithDuration:1 animations:^{
        [self layoutIfNeeded];
    } completion:^(BOOL finished) {
        //repeat!
        [self animateWithInvertedInsets:!invertedInsets];
    }];

通過取里面的某一個(gè)constraint,來修改部分屬性達(dá)到更新約束形成動(dòng)畫的效果
這里設(shè)置的是insetsd的屬性,我們也可以試試其他的屬性

后面的MASExampleDebuggingView我就不再詳細(xì)說明了,是輔助查看約束的值的,方便檢查約束是否正確


這里寫圖片描述

我們可以在consle中看到自己自定的key和約束的值

接下來的是MASExampleLabelView
約束什么的就不說了
關(guān)注的是

- (void)layoutSubviews {
    [super layoutSubviews];

    // for multiline UILabel's you need set the preferredMaxLayoutWidth
    // you need to do this after [super layoutSubviews] as the frames will have a value from Auto Layout at this point

    // stay tuned for new easier way todo this coming soon to Masonry

    CGFloat width = CGRectGetMinX(self.shortLabel.frame) - kPadding.left;
    width -= CGRectGetMinX(self.longLabel.frame);
    self.longLabel.preferredMaxLayoutWidth = width;

    // need to layoutSubviews again as frames need to recalculated with preferredLayoutWidth
    [super layoutSubviews];
}

這里有說明需要設(shè)置多行l(wèi)abel的時(shí)候你需要設(shè)置最大寬度,你需要在[super layoutSubviews]之后設(shè)置一個(gè)值,這樣其寬度就能夠設(shè)置成功,再之后所有的約束就都是正確的了,原因是在makeConstraints中我們看到只是設(shè)置了左上,確定了位置,但是沒有固定大小,所以需要設(shè)置寬度之后才能確定label的高度,才能繼續(xù)其他的依賴他的約束

我們?cè)俳又碝ASExampleScrollView
我們知道,scrollerView是一個(gè)可以拖動(dòng)的view,其是有一個(gè)contentSize屬性的,如果沒有設(shè)置好的話,其可能會(huì)導(dǎo)致無法下拉到底部等問題,xib我們就會(huì)遇到這樣的問題,有時(shí)候很難解決,我們看看Masonry是如何實(shí)現(xiàn)的

[contentView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.scrollView);
        make.width.equalTo(self.scrollView);
    }];
[contentView makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(lastView.bottom);
    }];

上面先給scrollerView添加一個(gè)contentView,然后設(shè)置其位置和大小即可.是不是很方便,不需要再設(shè)置contentSize了,這里用到了bottom
這里需要補(bǔ)充自動(dòng)布局的情況下去定義contentSize是無效的。而mas_leading,mas_trailing是根據(jù)contentSize來確定的具體位置环壤,而不是根據(jù)scrollview的frame來確定晒来,因此布局得到的并不是想要得到的結(jié)果。(相互依賴)
如果設(shè)置了scrollView的contentSize镐捧,但是實(shí)際上在自動(dòng)布局的情況下潜索,contentSize的大小并不是原先設(shè)置的那樣,而是由內(nèi)容約束來定義的(leading,trailing)懂酱,后執(zhí)行的Masonry布局代碼重定義了contentSize竹习。
contentSize的height同理,由top列牺,bottom來決定
為什么上面的可以滑動(dòng)了呢?因?yàn)槲覀冊(cè)O(shè)置了contentView的上下左右,所以scrollerView自動(dòng)布局后的contentSize就是contentView的大小

接下來是MASExampleArrayView,
這里的思想是把幾個(gè)控件放在一起控制約束

- (void)setOffset:(CGFloat)offset {
    _offset = offset;
    [self setNeedsUpdateConstraints];
}

- (void)updateConstraints {
    [self.buttonViews updateConstraints:^(MASConstraintMaker *make) {
        make.baseline.equalTo(self.mas_centerY).with.offset(self.offset);
    }];
    
    //according to apple super should be called at end of method
    [super updateConstraints];
}

這里的buttonViews是一個(gè)數(shù)組,數(shù)組里面是多個(gè)控件.至于約束的內(nèi)容還是之前學(xué)習(xí)的那些,不做描述

來到MASExampleAttributeChainingView
還是熟悉的界面,三個(gè)視圖

[greenView mas_makeConstraints:^(MASConstraintMaker *make) {
        // chain attributes
        make.top.and.left.equalTo(superview).insets(padding);

        // which is the equivalent of
//        make.top.greaterThanOrEqualTo(superview).insets(padding);
//        make.left.greaterThanOrEqualTo(superview).insets(padding);

        make.bottom.equalTo(blueView.mas_top).insets(padding);
        make.right.equalTo(redView.mas_left).insets(padding);
        make.width.equalTo(redView.mas_width);

        make.height.equalTo(@[redView, blueView]);
    }];

    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        // chain attributes
        make.top.and.right.equalTo(superview).insets(padding);

        make.left.equalTo(greenView.mas_right).insets(padding);
        make.bottom.equalTo(blueView.mas_top).insets(padding);
        make.width.equalTo(greenView.mas_width);

        make.height.equalTo(@[greenView, blueView]);
    }];

    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(greenView.mas_bottom).insets(padding);

        // chain attributes
        make.left.right.and.bottom.equalTo(superview).insets(padding);

        make.height.equalTo(@[greenView, redView]);
    }];

至于約束還是之前的約束,要講的是什么呢? 其實(shí)在之前已經(jīng)說過了,上面采用了蓮式思想來進(jìn)行約束,采用. 將多個(gè)屬性進(jìn)行連接成一句話
make.left.right.and.bottom.equalTo(superview).insets(padding); 很簡單的意思,讓左右下都等于某一個(gè)約束值,這里順序沒有要求,and 可以理解成連接,沒有任何作用,僅作為讀寫順暢.

接下來MASExampleMarginView就不多說了,我們使用過xib就會(huì)知道,在iOS8.0之后使用約束的時(shí)候會(huì)有一個(gè)Margin屬性


這里寫圖片描述

至于意思就是會(huì)做一個(gè)保留值,而不是從0開始為從8開始的一個(gè)縮進(jìn),這個(gè)大家使用xib實(shí)驗(yàn)一下就知道了

至于MASExampleDistributeView,我們可以看到界面


這里寫圖片描述

幫我們實(shí)現(xiàn)了等距的效果,類似iOS9中的UIStackView.
總共有4種實(shí)現(xiàn),我們分別測試看看

[arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
            [arr makeConstraints:^(MASConstraintMaker *make) {
                make.top.equalTo(@60);
                make.height.equalTo(@60);
            }];
這里寫圖片描述

指定頂部和高度同時(shí)指定左右間距和中間修正間距所以中間的間距是5+20+5=30個(gè)像素....

[arr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
            [arr makeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(@0);
                make.width.equalTo(@60);
            }];
這里寫圖片描述

這是縱向的等距

說明一下

/**

  • 確定間距等間距布局
  • @param axisType 布局方向
  • @param fixedSpacing 兩個(gè)item之間的間距(最左面的item和左邊, 最右邊item和右邊都不是這個(gè))
  • @param leadSpacing 第一個(gè)item到父視圖邊距
  • @param tailSpacing 最后一個(gè)item到父視圖邊距
    */
  • (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;


[arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:30 leadSpacing:200 tailSpacing:30];
            [arr makeConstraints:^(MASConstraintMaker *make) {
                make.top.equalTo(@60);
                make.height.equalTo(@60);
            }];
這里寫圖片描述

這里有點(diǎn)變化,使用的是另一個(gè)方法

/**
 *  distribute with fixed item size
 *
 *  @param axisType  布局方向  
 *  @param fixedItemLength 每個(gè)item的布局方向的長度
 *  @param leadSpacing  第一個(gè)item到父視圖邊距
 *  @param tailSpacing  最后一個(gè)item到父視圖邊距
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

再看看最后一個(gè)

[arr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedItemLength:30 leadSpacing:30 tailSpacing:200];
            [arr makeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(@0);
                make.width.equalTo(@60);
            }];
這里寫圖片描述

我們可以看到兩者的不同,前面一個(gè)fixedItemLength代表的是寬度,后者則是高度,前面一個(gè)leadSpacing\tailSpacing代表的是x后面的代表的則是y,
這里我們只要稍稍關(guān)注一下就可以明白
有了這樣的API,我們以后再寫等距的代碼就真的很簡單了.而不需要天天拉約束,拉等比,拉長度......
另外我們還可以看到,總共是兩種方法,有什么區(qū)別呢?
對(duì)比下來我們可以看到,第一種方法重視的是等距,而不關(guān)心沒有個(gè)控件本身的寬高,只要求等距,第二個(gè)方法則相反,重視的是等大小,只控制控件本身大小,至于間距則是等分...
如此一來,我們真的很方便,無論是要求固定大小還是要求固定間距我們都能很好的實(shí)現(xiàn).

最后關(guān)心一下MASExampleLayoutGuideViewController

[topView makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.mas_topLayoutGuide);
        make.left.equalTo(self.view);
        make.right.equalTo(self.view);
        make.height.equalTo(@40);
    }];

    [topSubview makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.mas_topLayoutGuide);
        make.centerX.equalTo(@0);
        make.width.equalTo(@20);
        make.height.equalTo(@20);
    }];
    
    [bottomView makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.mas_bottomLayoutGuide);
        make.left.equalTo(self.view);
        make.right.equalTo(self.view);
        make.height.equalTo(@40);
    }];

我們可以看看效果


這里寫圖片描述

如果把make.top.equalTo(self.mas_topLayoutGuide); 改成我們平時(shí)想的make.top.equalTo(self.view); 會(huì)怎么樣呢?

這里寫圖片描述

OK 大致明白了,其實(shí)就是修正iOS中vc的view的frame帶來的位置偏移的因素,這里我就不說多少了.

至此,一個(gè)自動(dòng)布局框架Masonry的使用就學(xué)習(xí)完畢了,我們可以很輕松的使用期布局我們的界面,你會(huì)發(fā)現(xiàn)你再也不用糾結(jié)是使用xib還是storyboard還是使用手寫布局更方便了,你的代碼效率會(huì)大大提高的.
因?yàn)槠浯_實(shí)值得推薦...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末整陌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞎领,更是在濱河造成了極大的恐慌泌辫,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件九默,死亡現(xiàn)場離奇詭異震放,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驼修,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門殿遂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乙各,你說我怎么就攤上這事墨礁。” “怎么了耳峦?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵恩静,是天一觀的道長。 經(jīng)常有香客問我蹲坷,道長驶乾,這世上最難降的妖魔是什么邑飒? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮级乐,結(jié)果婚禮上幸乒,老公的妹妹穿的比我還像新娘。我一直安慰自己唇牧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布聚唐。 她就那樣靜靜地躺著丐重,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杆查。 梳的紋絲不亂的頭發(fā)上扮惦,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音亲桦,去河邊找鬼崖蜜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛客峭,可吹牛的內(nèi)容都是我干的豫领。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼舔琅,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼等恐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起备蚓,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤课蔬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后郊尝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體二跋,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年流昏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扎即。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡横缔,死狀恐怖铺遂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茎刚,我是刑警寧澤襟锐,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站膛锭,受9級(jí)特大地震影響粮坞,放射性物質(zhì)發(fā)生泄漏蚊荣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一莫杈、第九天 我趴在偏房一處隱蔽的房頂上張望互例。 院中可真熱鬧,春花似錦筝闹、人聲如沸媳叨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糊秆。三九已至,卻和暖如春议双,著一層夾襖步出監(jiān)牢的瞬間痘番,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工平痰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汞舱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓宗雇,卻偏偏與公主長得像昂芜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逾礁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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