Masonry使用詳解

Masonry -- 使用純代碼進(jìn)行iOS應(yīng)用的autolayout自適應(yīng)布局翅溺,對很多零散的進(jìn)行整理

?簡介

簡化iOS應(yīng)用使用純代碼機(jī)型自適應(yīng)布局的工作,使用一種簡潔高效的語法替代NSLayoutConstraints.

項(xiàng)目主頁:?Masonry

最新示例:?點(diǎn)擊下載

項(xiàng)目簡議: 如果再看到關(guān)于純代碼,xib或storyboard,使用哪種方式進(jìn)行UI布局更合適的討論,請推薦他們先試用下 Masonry. Masonry,像xib一樣快速,同時擁有作為純代碼方式的靈活性 -- github關(guān)注度 7800 + 是有原因的!

快速入門

安裝

使用 CocoaPods 安裝

```

pod 'Masonry'

```

推薦在你的在 prefix.pch 中引入頭文件:

```

// 定義這個常量,就可以在使用Masonry不必總帶著前綴 `mas_`:

#define MAS_SHORTHAND

// 定義這個常量,以支持在 Masonry 語法中自動將基本類型轉(zhuǎn)換為 object 類型:

#define MAS_SHORTHAND_GLOBALS

#import "Masonry.h"

```

使用

初始Masonry

這是使用MASConstraintMaker創(chuàng)建的約束:

```

/* 注意:view1應(yīng)首先添加為某個視圖的子視圖,superview是一個局部變量,指view1的父視圖. */

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

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(superview.mas_top).offset(padding.top);

make.left.equalTo(superview.mas_left).offset(padding.left);

make.bottom.equalTo(superview.mas_bottom).offset(-padding.bottom);

make.right.equalTo(superview.mas_right).offset(-padding.right);

}];

```

甚至可以更短:

```

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {

make.edges.equalTo(superview).insets(padding);

}];

```

## 不止可以表達(dá)相等關(guān)系

> `.equalTo` 等價(jià)于 NSLayoutRelationEqual

> `.lessThanOrEqualTo` 等價(jià)于 NSLayoutRelationLessThanOrEqual

> `.greaterThanOrEqualTo` 等價(jià)于 NSLayoutRelationGreaterThanOrEqual

這三個表達(dá)相等關(guān)系的語句,可以接受一個參數(shù);此參數(shù)可以為以下任意一個:

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

自適應(yīng)布局允許將寬度或高度設(shè)置為固定值.如果你想要給視圖一個最小或最大值,你可以這樣:

```

//width >= 200 && width <= 400

make.width.greaterThanOrEqualTo(@200);

make.width.lessThanOrEqualTo(@400)

```

但是自適應(yīng)布局不支持將 left,right, centerY等設(shè)為固定值.如果你給這些屬性傳遞一個常量, Masonry會自動將它們轉(zhuǎn)換為相對于其父視圖的相對值:

```

//creates view.left = view.superview.left + 10

make.left.lessThanOrEqualTo(@10)

```

除了使用 NSNumber 外,你可以使用基本數(shù)據(jù)類型或者結(jié)構(gòu)體來創(chuàng)建約束:

```

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));

```

4、NSArry

一個數(shù)組,里面可以混合是前述三種類型的任意幾種:

```

// 表達(dá)三個視圖等高的約束.

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

make.height.equalTo(@[view1, view2]);

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

```

#### 兩個特殊的等比方法

* 第一種

![](http://upload-images.jianshu.io/upload_images/2162015-da44bf4b329efc83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```

//在紅色View里面放三個正方形View, 等間距為10

NSInteger padding = 10;

UIView *yellowView1 = [[UIView alloc] init];

yellowView1.backgroundColor = [UIColor yellowColor];

[redView addSubview:yellowView1];

UIView *yellowView2 = [[UIView alloc] init];

yellowView2.backgroundColor = [UIColor yellowColor];

[redView addSubview:yellowView2];

UIView *yellowView3 = [[UIView alloc] init];

yellowView3.backgroundColor = [UIColor yellowColor];

[redView addSubview:yellowView3];

[@[yellowView1, yellowView2, yellowView3] mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:padding leadSpacing:padding tailSpacing:padding];

[@[yellowView1, yellowView2, yellowView3] mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(redView).offset(10);

make.height.mas_equalTo(yellowView3.mas_width);

}];

```

```

/**

*? 確定間距等間距布局

*

*? @param axisType? ? 布局方向

*? @param fixedSpacing 兩個item之間的間距(最左面的item和左邊, 最右邊item和右邊都不是這個)

*? @param leadSpacing? 第一個item到父視圖邊距

*? @param tailSpacing? 最后一個item到父視圖邊距

*/

- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

```

所以也就知道了, 將`fixedSpacing`, `leadSpacing`, `tailSpacing`都賦值同一個間距, 數(shù)組內(nèi)的的View就會自動計(jì)算出寬度, 完成水平方向的布局.

要注意的是, 這個方法僅僅完成了水平方向的布局, 如果想確定這幾個View的位置, 還需要指定豎直方向位置和高度, 這里可以用數(shù)組直接調(diào)用 `mas_makeConstraints:^(MASConstraintMaker *make){}`完成布局.

* 第二種

![](http://upload-images.jianshu.io/upload_images/2162015-f1e9484bda5f5612.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```

/**

*? distribute with fixed item size

*

*? @param axisType? 布局方向

*? @param fixedItemLength 每個item的布局方向的長度

*? @param leadSpacing? 第一個item到父視圖邊距

*? @param tailSpacing? 最后一個item到父視圖邊距

*/

- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

```

區(qū)別就是這里除了布局方向, 第一個和最后一個View的邊距, 這里需要指定的是每個item的長度, 自動計(jì)算間隙, 所以這個要實(shí)現(xiàn)等間距, 其實(shí)是要通過item的數(shù)量, 以及父視圖的寬度先計(jì)算出間距, 然后賦值給, leadSpacing和tailSpacing, 比如`CGFloat padding2 = (300 - 3 * 30) / 4;` 這里的300就是父視圖的寬度, 30是指定的每個item的寬度, 這樣計(jì)算好就可以保證, leadSpacing, tailSpacing, 和item之間的間距相同, 實(shí)現(xiàn)布局.

同樣這個方法完成了水平方向的布局, 還需要完成豎直方向的布局.

* 第三種

![](http://upload-images.jianshu.io/upload_images/2162015-4cc19492281e48fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```

//在紅色View里面放三個大小不一樣的綠色正方形, 間隙等大, masonry并沒提供相關(guān)方法

NSMutableArray *greenViews = [NSMutableArray array];

for (NSInteger i = 0; i < 3; i++) {

UIView *greenView = [[UIView alloc] init];

greenView.backgroundColor = [UIColor greenColor];

[redView addSubview:greenView];

[greenViews addObject:greenView];

[greenView mas_makeConstraints:^(MASConstraintMaker *make) {

make.bottom.equalTo(redView).offset(-10);

make.width.mas_equalTo(i*20 + 20);

make.height.mas_equalTo(greenView.mas_width);

}];

}

[redView distributeSpacingHorizontallyWith:greenViews];

```

首先在for循環(huán)內(nèi) , 完成了底部位置, 寬, 高的布局, 還缺少水平方向的位置, 即還要確定每個view的X, 這里用到了一個UIView的分類

`- (void) distributeSpacingHorizontallyWith:(NSArray*)views;`

這個分類直接用的里脊串的一篇文章中的代碼, 就不貼出代碼了, 簡單說一下原理, 如圖所示:

![](http://upload-images.jianshu.io/upload_images/2162015-7611cd1ea333175e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

實(shí)現(xiàn)原理就是在View中創(chuàng)建greenViews.count + 1個占位的View(藍(lán)色), 之后通過布局, 使占位View與要布局的View依次排開, 左右間距為0, 同時要約束所有的占位View寬度相等, 這樣看來, 這些占位View的寬度, 就是greenViews的間距, 也就可以實(shí)現(xiàn)等間距布局了.

## 約束的優(yōu)先級

> `.priority` 允許你指定一個精確的優(yōu)先級,數(shù)值越大優(yōu)先級越高.最高1000.

> `.priorityHigh` 等價(jià)于 UILayoutPriorityDefaultHigh.優(yōu)先級值為 750.

> `.priorityMedium` 介于高優(yōu)先級和低優(yōu)先級之間,優(yōu)先級值在 250~750之間.

> `.priorityLow` 等價(jià)于 UILayoutPriorityDefaultLow, 優(yōu)先級值為 250.

優(yōu)先級可以在約束的尾部添加:

```

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

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

```

## 等比例自適應(yīng)

> `.multipliedBy` 允許你指定一個兩個視圖的某個屬性等比例變化

>

> `item1.attribute1 = multiplier × item2.attribute2 + constant`,此為約束的計(jì)算公式, `.multipliedBy`本質(zhì)上是用來限定 `multiplier`的

> 注意,因?yàn)榫幊讨械淖鴺?biāo)系從父視圖左上頂點(diǎn)開始,所以指定基于父視圖的left或者top的multiplier是沒有意義的,因?yàn)楦敢晥D的left和top總為0.

> 如果你需要一個視圖隨著父視圖的寬度和高度,位置自動變化,你應(yīng)該同時指定 right,bottom,width,height與父視圖對應(yīng)屬性的比例(基于某個尺寸下的相對位置計(jì)算出的比例),并且constant必須為0.

```

// 指定寬度為父視圖的 1/4.

make.width.equalTo(superview).multipliedBy(0.25);

```

## 工具方法

Masonry提供了一些工具方法來進(jìn)一步簡化約束的創(chuàng)建.

### edges 邊界

```

//使 top, left, bottom, right等于 view2

make.edges.equalTo(view2);

//使 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 尺寸

```

// 使寬度和高度大于或等于 titleLabel

make.size.greaterThanOrEqualTo(titleLabel)

//使 width = superview.width + 100, height = superview.height - 50

make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))

```

### center 中心

```

//使 centerX和 centerY = button1

make.center.equalTo(button1)

//使 centerX = superview.centerX - 5, centerY = superview.centerY + 10

make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))

```

你可以使用鏈?zhǔn)秸Z法來增強(qiáng)代碼可讀性:

```

// 除top外,其他約束都與父視圖相等.

make.left.right.bottom.equalTo(superview);

make.top.equalTo(otherView);

```

## 更新約束

有時,你需要修改已經(jīng)存在的約束來實(shí)現(xiàn)動畫效果或者移除/替換已有約束.在 Masonry 中,有幾種不同的更新視圖約束的途徑:

#### 1灾前、References 引用

你可以把 Masonry 語法返回的約束或約束數(shù)組,存儲到一個局部變量或者類的屬性中,以供后續(xù)操作某個約束.

```

// 聲明屬性

@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);

}];

...

// 然后你就可以操作這個屬性.

[self.topConstraint uninstall];

```

#### 2防症、mas_updateConstraints

如果你只是想添加新的約束,你可以使用便利方法mas_updateConstraints,不需要使用 mas_makeConstraints. mas_updateConstraints,不會移除已經(jīng)存在的約束(即使新舊約束間相互沖突).

```

// 重寫視圖的updateConstraints方法: 這是Apple推薦的添加/更新約束的位置.

// 這個方法可以被多次調(diào)用以響應(yīng)setNeedsUpdateConstraints方法.

// setNeedsUpdateConstraints 可以被UIKit內(nèi)部調(diào)用或者由開發(fā)者在自己的代碼中調(diào)用以更新視圖約束.

- (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);

}];

//根據(jù)apple機(jī)制,最后應(yīng)調(diào)用父類的updateConstraints方法.

[super updateConstraints];

}

```

#### 3. mas_remakeConstraints

`mas_remakeConstraints`與`mas_updateConstraints`相似,不同之處在于: `mas_remakeConstraints` 會先移除視圖上已有的約束,再去創(chuàng)建新的約束.

```

- (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);

}

}];

}

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哎甲,隨后出現(xiàn)的幾起案子蔫敲,更是在濱河造成了極大的恐慌,老刑警劉巖炭玫,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奈嘿,死亡現(xiàn)場離奇詭異,居然都是意外死亡吞加,警方通過查閱死者的電腦和手機(jī)裙犹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衔憨,“玉大人叶圃,你說我怎么就攤上這事∥撞疲” “怎么了盗似?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長平项。 經(jīng)常有香客問我赫舒,道長,這世上最難降的妖魔是什么闽瓢? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任接癌,我火速辦了婚禮,結(jié)果婚禮上扣讼,老公的妹妹穿的比我還像新娘缺猛。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布荔燎。 她就那樣靜靜地躺著耻姥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪有咨。 梳的紋絲不亂的頭發(fā)上琐簇,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音座享,去河邊找鬼婉商。 笑死,一個胖子當(dāng)著我的面吹牛渣叛,可吹牛的內(nèi)容都是我干的丈秩。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼淳衙,長吁一口氣:“原來是場噩夢啊……” “哼蘑秽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起滤祖,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤筷狼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后匠童,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埂材,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年汤求,在試婚紗的時候發(fā)現(xiàn)自己被綠了俏险。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡扬绪,死狀恐怖竖独,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挤牛,我是刑警寧澤莹痢,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站墓赴,受9級特大地震影響竞膳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诫硕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一坦辟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧章办,春花似錦锉走、人聲如沸滨彻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亭饵。三九已至,卻和暖如春嚣潜,著一層夾襖步出監(jiān)牢的瞬間冬骚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工懂算, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庇麦。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓计技,卻偏偏與公主長得像,于是被迫代替她去往敵國和親山橄。 傳聞我的和親對象是個殘疾皇子垮媒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

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

  • 一、前言 關(guān)于蘋果的布局一直是我比較糾結(jié)的問題航棱,是寫代碼來控制布局睡雇,還是使用storyboard來控制布局呢?以前...
    iplaycodex閱讀 2,458評論 0 1
  • Masonry是一個輕量級的布局框架饮醇,擁有自己的描述語法它抱,采用更優(yōu)雅的鏈?zhǔn)秸Z法封裝自動布局,簡潔明了并具有高可讀性...
    3dcc6cf93bb5閱讀 1,771評論 0 1
  • (一)Masonry介紹 Masonry是一個輕量級的布局框架 擁有自己的描述語法 采用更優(yōu)雅的鏈?zhǔn)秸Z法封裝自動布...
    木易林1閱讀 2,347評論 0 3
  • iOS_autoLayout_Masonry 概述 Masonry是一個輕量級的布局框架與更好的包裝AutoLay...
    指尖的跳動閱讀 1,169評論 1 4
  • Pink Floyd的《迷墻》燃起我對搖滾樂的興趣朴艰,然而我在嘗試欣賞Pink的其他作品時卻再難感受到观蓄,來自心的觸動...
    社長墨非閱讀 223評論 0 0