** 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
使用
在你的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不會用宏污染全局命名空間窘问。不是字符串或字典,因此您可以編譯時間檢查宜咒。