1、label約束:
1)、只需約束x、y 點相關就行。寬高 長度相關不用約束,就算用boundingRectWithSize計算出來的,也可能不准。
如:top、bottom二選一,trailing、leading二選一,或者center,寬高會自動生成。(同時約束trailing、leading的話,相當於設了寬度)
2)、有些地方怕label過長超出,或覆蓋其他控件,這時就需要約束 寬高,讓其“...”。
后續補充:還是沒必要約束寬,可以讓top、bottom、trailing、leading設置 lessThanOrEqualTo 屬性。
小於正常顯示,大於會省略號,比起 equalTo 寬,寫死的,會好用些
比如高寫死的話,會發現,字體垂直居中,這樣就和左邊的“標題Label”,水平不對齊了
1)、lessThanOrEqualTo:小於或等於(注意負號)( label 有個最大寬度屬性 preferredMaxLayoutWidth,有點像? )
2)、equalTo:等價於
3)、greaterThanOrEqualTo:大於或等於(注意負號)
3)、垂直約束,我更喜歡用centerY。
用top的話:1)、UI的字體大小和iOS可能會有偏差,多行label,誤差就越大。而設中心點,他是中心定點,上下伸縮。
2)、如果又有一個控件,如ImageView,跟label的Y軸中心對齊,而label,用top對齊其他且當前label.text = nil,會出錯(好像此時label的center會等於top)。
2、在cell重用里刷新數據,要用更新約束:mas_updateConstraints 或 重新約束:mas_remakeConstraints。
后續補充:3種常用
1)、mas_makeConstraints:約束
2)、mas_updateConstraints:更新相同的約束對象數據,如寬。
3)、mas_remakeConstraints:重新約束所有
再補充:也沒必要一直在cell里改約束。比如,cell里經常修改一個label的約束的時候,
1)、可以考慮多弄幾個樣式的label,當前不需要的label隱藏。
2)、可以通過 安裝、卸載 。在初始化的時候,定好約束優先級。
3、UIPageControl小圓點、UISwitch開關,約束 center/ top、bottom / trailing、leading 等x、y 點即可。
4、約束centerX/centerY,容易犯的錯
make.centerX.mas_equalTo(10.0); make.centerX.offset(10.0);
語句看起來,像是給centerX = 10.0的數值,然而效果卻是父視圖的centerX + 10.0,
原因,參照下面的附錄,它自動默認一樣的屬性。應該寫詳細點。
make.centerX.mas_equalTo(self.view.mas_leading).offset(10.0);
再補充:如果1個固定的控件和1個移動的控件(下划線)centerX,約束一樣,如,make.centerX.mas_equalTo(固定.mas_centerX),
接着,想通過mas_updata,更新centerX到另一個控件,會發現約束沖突,連固定的控件一起移動。
解決,取另一個參照物。
1)、newCenterX = 另一個控件.centerX 。
2)、make.centerX.mas_equalTo(固定.mas_leading).offset(newCenterX)
5、屬性
1)、之前用得較多的:top、bottom、trailing、leading、center、width、height
2)、現在開始用的 edges == top、bottom、trailing、leading。
insets 在 邊界約束好的基礎上,設置與父視圖的間隙,為正值!!也可以直接在edges里設置,一樣。
size == width、height。
sizeOffset 在 size 約束好的基礎上,進行增+減-。主要用於相對另一個View。
multipliedBy 倍數,比如0.5、1.5。不局限在相同屬性,也可以設置為自身 width 為 height 的3倍。
3)、center 配合 size 不錯。就像layer的 position 和 bound 。
6、父視圖contentView的寬高,有時候可以不用設置,它會根據子類去約束,比如移除某個子View,自動縮小、變化。
同時,也要注意因為父視圖缺少約束,而造成的“自動變化Bug”。
7、優先級 與 動畫( .priority(500) 或 UILayoutPriority 常量 )
在同一個控件做約束,可以設置兩個相同屬性的約束,對其優先級進行設置,會先找優先級高的約束。
優先級高約束有問題,會再向下尋找次之優先級的屬性約束。
默認優先級 UILayoutPriorityRequired == 1000 。
后續補充:同一屬性、同一優先級,多個約束也沒問題。不過都得是greaterThanOrEqualTo、lessThanOrEqualTo的約束。
使用參照“8、優先級與邊界”。
再補充:比如網絡請求,加載到數據,給當前內容為nil的控件寫入數據的時候(例如,當前 空的昵稱label、空的性別圖片 ,沒顯示出來)
多寫一行 UIView animation + layoutIfNeeded ,有意想不到的效果。
對 再補充 補充:使用 UIView animation + layoutIfNeeded 做動畫的情況下,
可使用 [self.animationView.layer removeAllAnimations]; 移除動畫,如需可用 block 的 finished 判斷是否完成動畫
[UIView animateWithDuration:8.0
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
// 動畫
[self layoutIfNeeded];
} completion:^(BOOL finished) {
// 動畫完成
[self.animationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(SCREEN_WIDTH);
}];
}];
再再補充:做彈窗動畫,如果初始化為約束,做動畫也用 約束+ UIView animation + layoutIfNeeded,在第一次(懶)加載的時候會導致所有的控件一起動畫,
可先在初始化的時候 [self setNeedsLayout] + [self layoutIfNeeded] ,完成UI布局。
1)、如 移除優先級高的參照物,再layout。就可以做動畫。
[view mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(參照物1.mas_trailing).offset(20).priority(750); make.leading.equalTo(參照物2.mas_trailing).offset(20).priority(250); }]; [參照物1 removeFromSuperview]; [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }];
2)、或者提取出來
2-1)、卸載掉該約束
MASConstraint *leadingMas; [view mas_makeConstraints:^(MASConstraintMaker *make) { leadingMas = make.leading.equalTo(參照物1.mas_trailing).offset(20).priority(750); make.leading.equalTo(參照物2.mas_trailing).offset(20).priority(250); }]; [leadingMas uninstall]; [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }];
后續補充:卸載uninstall、安裝install 可以重復。只要變量沒釋放
2-2)、修改約束。
MASConstraint *widthMas; [view mas_makeConstraints:^(MASConstraintMaker *make) { widthMas = make.width.equalTo(50); }]; widthMas.equalTo(100); [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }];
3)、也可以用 mas_updateConstraints 對同一屬性進行更新
[view mas_updateConstraints:^(MASConstraintMaker *make) { make.width.equalTo(100); }]; [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }];
8、優先級與邊界
1)、初始化
@property (nonatomic,strong) MASConstraint *topMas; @property (nonatomic,strong) MASConstraint *leadingMas; [self.moveView mas_makeConstraints:^(MASConstraintMaker *make) { // 邊界。不寫優先級,默認優先級最高 = UILayoutPriorityRequired = 1000 make.leading.top.greaterThanOrEqualTo(self.bgView); make.trailing.bottom.lessThanOrEqualTo(self.bgView); // 確定寬高 make.width.mas_equalTo(50); make.height.mas_equalTo(50); // 確定位置。高優先級,可變動的位置。 self.topMas = make.top.equalTo(self.bgView).offset(50).priority(750); self.leadingMas = make.leading.equalTo(self.bgView).offset(50).priority(750); }];
后續補充:寬高看情況判斷是否需要約束。
2)、改變位置
2-1)、改動 make 返回的數據
self.topMas.offset(100); self.leadingMas.offset(100);
2-2)、直接更新約束
[self.moveView mas_updateConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(self.bgView).offset(100).priority(750); make.leading.mas_equalTo(self.bgView).offset(100).priority(750); }];
補充,2-1)比 2-2)需要多存2個變量,且只能修改offset,無法改之前的參照物、優先級。
但是,寫法更簡潔,適合改動少的。
優先級,可以自定宏,也可以用系統給 UILayoutPriorityDefaultHigh = 750 、UILayoutPriorityDefaultLow = 250。
再補充:邊界,也可以在拖動的時候判斷x、y、x+width、y+height,純手工計算。
9、如果兩個並排的lable。
1)、在字數(寬高)可能相互擠壓的時候,可以優先保護某個Label的完整性
// 水平位置,優先級高 [label1 setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal]; // 水平位置,優先級低(會被擠壓) [label2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
后續補充:setContentCompressionResistancePriority 為UIView的方法,設置抗壓性 優先級,第二個參數可選水平、垂直方向。
CompressionResistance 抗壓越高,則越不會被擠壓,如lable被擠壓,會顯示“...”。
相對的,有個 setContentHuggingPriority ,擁抱優先級,沒用過,應該是優先級越高,越不會被拉伸之類的把?!
2)、字體較少的時候,較空的地方可以用 lessThanOrEqualTo 。留空。
10、一些只要約束 位置 ,自動生成長寬的控件,如label,可以重寫 intrinsicContentSize ,添加內邊距,增大。
- (CGSize)intrinsicContentSize { CGSize tempSize = [super intrinsicContentSize]; return CGSizeMake(tempSize.width + insets.left + insets.right, tempSize.height + insets.top + insets.bottom); }
11、自動頂住 導航欄或狀態欄 , tabbar或底部
// self.mas_topLayoutGuide; // self.mas_bottomLayoutGuide; // self.mas_topLayoutGuideTop; // self.mas_topLayoutGuideBottom; // self.mas_bottomLayoutGuideTop; // self.mas_bottomLayoutGuideBottom; make.top.mas_equalTo(self.mas_topLayoutGuide);
12、baseLine。
不大熟悉。好像主要應用於,對齊兩個View里的子Lable,從而約束到View的位置。
重寫、以返回要對齊的baseView
iOS(6.0 - 9.0)
- (UIView *)viewForBaselineLayout { return baseView; }
iOS(9.0 - )
- (UIView *)viewForFirstBaselineLayout{ return baseView; } - (UIView *)viewForLastBaselineLayout{ return baseView; }
13、scrollView約束
scrollView,可視范圍正常約束,如:
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.mas_equalTo(self.view); }];
contentView,約束,如下(高度可變):
[scrollView addSubview:contentView]; [contentView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(scrollView); make.width.equalTo(scrollView); make.height.greaterThanOrEqualTo(@(0.f)); }];
需要的items,添加、約束到contentView上。
后續補充:忘了寫了,最后一個item的bottom要和contentView的bottom約束上,contentView才有確定的高
14、獲取上面剛約束完的尺寸,來設置別的view.frame。要先layout,否則可能獲取到{0, 0, 0, 0}。
[self layoutIfNeeded];
附錄:
例、兩個並排的按鈕
//equalTo 比較 View, //mas_equalTo 比較 數值 //如果在 redButton 里約束有用到 greenButton ,則 greenButton 在之前就要添加到和 redButton 同一父類View下。 紅色的按鈕(equalTo) UIButton *redButton = [[UIButton alloc]init]; redButton.backgroundColor = [UIColor redColor]; [self.view addSubview:redButton]; [redButton mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@100); make.leading.equalTo(self.view).offset(10.0); make.bottom.equalTo(self.view).offset(-10.0); }]; 綠色的按鈕(mas_equalTo) 1)、比較全的寫法 UIButton *greenButton = [[UIButton alloc]init]; greenButton.backgroundColor = [UIColor greenColor]; [self.view addSubview:greenButton]; [greenButton mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(100); make.width.mas_equalTo(redButton.mas_width); make.trailing.mas_equalTo(self.view.mas_trailing).offset(-10.0); make.bottom.mas_equalTo(self.view.mas_bottom).offset(-10.0); make.leading.mas_equalTo(redButton.mas_trailing).offset(10.0); }]; 2)、如果屬性是一樣的,可以省略后面的屬性 make.width.mas_equalTo(redButton); make.trailing.mas_equalTo(self.view).offset(-10.0); make.bottom.mas_equalTo(self.view).offset(-10.0); 3)、相對於(2),甚至可以寫0,相對父視圖。寬可不能跟着寫0,寬0就0了 make.trailing.mas_equalTo(0).offset(-10.0); make.bottom.mas_equalTo(0).offset(-10.0); 4)、相對於(3),既然都可以0,那干脆直接去掉 make.trailing.offset(-10.0); make.bottom.offset(-10.0);