Masonry使用技巧
masonry git地址:https://github.com/SnapKit/Masonry
本文主要會講到masonry英文文檔(見上面的git地址)中提及到的使用說明,以及個人使用過程中的一些經驗,僅適用一些剛使用masonry的新手,大牛可以忽略,當然也可以進來指點。
一、常用的屬性與常量
1. MASViewAttribute 以對應的系統類型
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
先來一波最爲常用的使用方法,大家可以看一下大致語法,下面會細講使用
//.分別設置各個相對邊距(superview爲view的父類視圖,下同)
make.left.mas_equalTo(superView.mas_left).mas_offset(10);
make.right.mas_equalTo(superView.mas_right).mas_offset(-10);
make.top.mas_equalTo(superView.mas_top).mas_offset(10);
make.bottom.mas_equalTo(superView.mas_bottom).offset(-10);
//直接連接使用left大於等於每個值
make.left.mas_greaterThanOrEqualTo(10);
//設置寬和高
make.width.mas_equalTo(60);
make.height.mas_equalTo(60);
//.設置center和款高比
make.center.mas_equalTo(superView);
make.width.mas_equalTo(superView).multipliedBy(1.00/3);
make.height.mas_equalTo(superView).multipliedBy(0.25);
//.關於約束優先級,此處要注意約束衝突的問題,統一約束優先級大的生效
make.left.mas_equalTo(100);
make.left.mas_equalTo(view.superview.mas_left).offset(10);
make.left.mas_equalTo(20).priority(700);
make.left.mas_equalTo(40).priorityHigh();
make.left.mas_equalTo(60).priorityMedium();
make.left.mas_equalTo(80).priorityLow();
//.如果你想讓view的(x座標)左邊大於等於label的左邊,以下兩個約束的寫法效果一樣
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);
注:約束的鏈式寫法中,不包含其他相對的view時,默認爲其superview,即make.left.mas_equalTo(100);
等價於make.left.mas_equalTo(view.superview.mas_left).offset(10);
和make.left.mas_equalTo(view.superview).offset(10);
3. NSNumber
自動佈局允許使用常量去設置寬或高,如果你想通過一個數字設置一個view的最小和最大的width,可以用equality blocks,如下:
//width >= 200 && width <= 400
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)
然而自動佈局不允許對齊屬性的約束(如:left,right,centerY等)設置爲常量值,你可以使用NSNumber來設置相對於父類view這些約束屬性,如:
// creates 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_前綴,如果你不想添加此前綴,但還想使用常量值設置約束,需要在導入Masonry頭文件前,設置宏定義MAS_SHORTHAND_GLOBALS,至於爲什麼,去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允許你設置一個非常準確的的約束優先級(0-1000)
.priorityHigh 相當於系統的 UILayoutPriorityDefaultHigh
.priorityMedium 介於 high and low之間的優先級
.priorityLow 相當於系統的 UILayoutPriorityDefaultLow
注:默認通過mas_make添加的約束不設置優先級時,默認都是最高(1000)
優先級屬性可以放在約束鏈的末端使用,如:
make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();
make.top.equalTo(label.mas_top).with.priority(600);
三、更加便利的約束方法
Masonry提供了一些便利的方法供我們同時創建多個不同的約束,他們被稱爲MASCompositeConstraints,如:
edges
// 使一個view的top, left, bottom, right 等於view2的
make.edges.equalTo(view2);
//相對於superviewde上左下右邊距分別爲5,10,15,20
make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20))
size
// 使得寬度和高度大於等於 titleLabel
make.size.greaterThanOrEqualTo(titleLabel)
// 相對於superview寬度大100,高度小50
make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50))
center
//中心與button1對齊
make.center.equalTo(button1)
//水平方向中心相對向左偏移5,豎直方向中心向下偏移10
make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))
你可以在約束鏈裏添加相應的view來增加代碼的可讀性:
// 除了top,所有的邊界與superview對齊
make.left.right.and.bottom.equalTo(superview);
make.top.equalTo(otherView);
四、關於如何修改約束
有時候,你爲了實現動畫或者移除替換一些約束時,你需要去修改一些已經存在的約束,Masonry提供了一些不同的方法去更新約束,你也可以將多個約束存在數組裏
1. References
你可以持有某個特定的約束,讓其成爲成員變量或者屬性
//設置爲公共或私接口
@property (nonatomic, strong) MASConstraint *topConstraint;
...
// 添加約束
[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];
//重新設置value,最常用
self.topConstraint.mas_equalTo(20);
//該約束失效
[self.topConstraint deactivate];
//該約束生效
[self.topConstraint activate];
2. mas_updateConstraints
如果你只是想更新一下view對應的約束,可以使用 mas_updateConstraints 方法代替 mas_makeConstraints方法
//這是蘋果推薦的添加或者更新約束的地方
// 在響應setNeedsUpdateConstraints方法時,這個方法會被調用多次
// 此方法會被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);
}];
//調用super
[super updateConstraints];
}
3. mas_remakeConstraints
mas_updateConstraints只是去更新一些約束,然而有些時候修改一些約束值是沒用的,這時候mas_remakeConstraints就可以派上用場了
mas_remakeConstraints某些程度相似於mas_updateConstraints,但不同於mas_updateConstraints去更新約束值,他會移除之前的view的所有約束,然後再去添加約束
- (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);
}
}];
五、在哪創建我的約束
貼一個官方說明的例子:
@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];
}
六、Layout必備知識
AutoLayout關於更新的幾個方法的區別
setNeedsLayout:告知頁面需要更新,但是不會立刻開始更新。執行後會立刻調用layoutSubviews。
layoutIfNeeded:告知頁面佈局立刻更新。所以一般都會和setNeedsLayout一起使用。如果希望立刻生成新的frame需要調用此方法,利用這點一般佈局動畫可以在更新佈局後直接使用這個方法讓動畫生效。
layoutSubviews:系統重寫佈局
setNeedsUpdateConstraints:告知需要更新約束,但是不會立刻開始
updateConstraintsIfNeeded:告知立刻更新約束
updateConstraints:系統更新約束
七、使用tips
- 給view添加約束時,必須已經添加到其superview上面
- 不需要設置
view.translatesAutoresizingMaskIntoConstraints = NO;
,masonry內部已經幫我設置過了 - 手寫佈局時,合理使用約束,儘量約束衝突問題
- 因爲iOS中原點在左上角所以注意使用offset時注意right和bottom用負數
推薦兩個大牛寫的關於Masonry源碼解析的博客
文章轉載自:https://www.jianshu.com/p/f5883db2411d