Masonry
是一個輕量級的佈局框架,它擁有本身的描述語法(採用更優雅的鏈式語法封裝)來自動佈局,具備很好可讀性且同時支持iOS和Max OS X
等。
總之,對於側重寫代碼的coder,請你慢慢忘記Frame
,喜歡Masonry
吧ios
如果你對於自動佈局很熟練的話,再接觸這個第三方
Masonry
很容易上手的,對UI界面顯示的控件的約束本質都是相同的,如今呢,我通常都是喜歡在控制器裏導入#import "Masonry.h"
以前再添加兩個宏,來提升App的開發效率。git
//1. 對於約束參數能夠省去"mas_" #define MAS_SHORTHAND
//2. 對於默認的約束參數自動裝箱 #define MAS_SHORTHAND_GLOBALS
即:須要咱們導入的框架與宏以下github
//define this constant if you want to use Masonry without the 'mas_' prefix #define MAS_SHORTHAND //define this constant if you want to enable auto-boxing for default syntax #define MAS_SHORTHAND_GLOBALS #import "Masonry.h" //宏必須添加在頭文件前面
添加約束前提:被約束的必須有父控件,其中約束項都必須是
UIView或子類的實例
。數組
約束的屬性app
在此我就列舉幾個可能不太熟悉的吧框架
@property (nonatomic, strong, readonly) MASConstraint *leading; //首部 @property (nonatomic, strong, readonly) MASConstraint *trailing; //尾部 @property (nonatomic, strong, readonly) MASConstraint *baseline; //文本基線
/** //這個方法只會添加新的約束 [blueView mas_makeConstraints:^(MASConstraintMaker *make) { }]; // 這個方法會將之前的全部約束刪掉,添加新的約束 [blueView mas_remakeConstraints:^(MASConstraintMaker *make) { }]; // 這個方法將會覆蓋之前的某些特定的約束 [blueView mas_updateConstraints:^(MASConstraintMaker *make) { }]; */ `
/** 1.尺寸:width、height、size 2.邊界:left、leading、right、trailing、top、bottom 3.中心點:center、centerX、centerY 4.邊界:edges 5.偏移量:offset、insets、sizeOffset、centerOffset 6.priority()約束優先級(0~1000),multipler乘因數, dividedBy除因數 */
使用
Masonry
不須要設置控件的translatesAutoresizingMaskIntoConstraints
屬性爲NO
;
防止block
中的循環引用,使用弱引用(這是錯誤觀點),在這裏block
是局部的引用,block
內部引用self
不會形成循環引用的
__weak typeof (self) weakSelf = self
;(不必的寫法)less
當約束衝突發生的時候,咱們能夠設置view的key來定位是哪一個view
redView.mas_key = @"redView";
greenView.mas_key = @"greenView";
blueView.mas_key = @"blueView";
如果以爲這樣一個個設置比較繁瑣,怎麼辦呢,Masonry則提供了批量設置的宏MASAttachKeys
MASAttachKeys(redView,greenView,blueView); //一句代碼便可所有設置dom
約束iconView
距離各個邊距爲30ide
[iconView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(30, 30, 30, 30)); }];
#define mas_equalTo(...) equalTo(MASBoxValue((__VA_ARGS__))) #define mas_greaterThanOrEqualTo(...) greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__))) #define mas_lessThanOrEqualTo(...) lessThanOrEqualTo(MASBoxValue((__VA_ARGS__))) #define mas_offset(...) valueOffset(MASBoxValue((__VA_ARGS__)))
得出結論:mas_equalTo
只是對其參數進行了一個BOX
(裝箱) 操做,目前支持的類型:數值類型(NSNumber)、 點(CGPoint)、大小(CGSize)、邊距(UIEdgeInsets)
,而equalTo:
這個方法不會對參數進行包裝。函數
//常見約束的寫法 這裏太簡單了 ,就不備註了 [iconView makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view).offset(-30); make.top.equalTo(self.view).offset(30); make.height.width.equalTo(100); //== make.size.equalTo(100); //make.size.mas_equalTo(self.view).multipliedBy(0.5); //make.top.greaterThanOrEqualTo(self.view).offset(padding); }];
[redView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(10); //with 加強可讀性 make.left.equalTo(greenView.mas_right).and.offset(10); //and 加強可讀性 make.bottom.equalTo(blueView.mas_top).offset(-10); make.right.equalTo(superview.mas_right).offset(-10); make.width.equalTo(greenView.mas_width); make.height.equalTo(@[greenView, blueView]); //約束參數相同能夠經過數組 }];
例如:控制器有個按鈕,如果點擊按鈕,則按鈕自己的大小、位置會隨機改變
[self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
處理事件
(void) didClickBtn:(UIButton *)button { self.btnSize = CGSizeMake(self.btnSize.width * 1.3, self.btnSize.height * 1.3); //設置一個屬性(btnSize)保存其大小的變化 //1.告知須要更新約束,但不會馬上開始,系統而後調用updateConstraints [self setNeedsUpdateConstraints]; //2.告知馬上更新約束,系統當即調用updateConstraints [self updateConstraintsIfNeeded]; //3.這裏動畫固然能夠取消,具體看項目的需求 //系統block內引用不會致使循環引用,block結束就會釋放引用對象 [UIView animateWithDuration:0.4 animations:^{ [self layoutIfNeeded]; //告知頁面馬上刷新,系統當即調用updateConstraints }]; }
蘋果官方建議:添加/更新約束在這個方法(updateConstraints)
內
// this is Apple's recommended place for adding/updating constraints - (void)updateConstraints { //更新約束 [self.btn 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]; }
requiresConstraintBasedLayout
爲YES+ (BOOL)requiresConstraintBasedLayout{ return YES ; //重寫這個方法 若視圖基於自動佈局的 }
對於控件的從新約束,則以前的約束都是無效的,步驟都更新約束同樣的,只是在updateConstraints
方法內的約束方法改成了remakeConstraints
,直接貼代碼吧(仍以按鈕爲例,其餘原理都是相同的)
//首先監聽按鈕 [self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside]; //處理事件 - (void) didClickBtn :(UIButton *)button{ (...) //觸發條件 [self setNeedsUpdateConstraints]; [self updateConstraintsIfNeeded]; /** * 動畫展現變化 - 這句代碼無關緊要,參考項目具體的需求 * [UIView animateWithDuration:0.4 animations:^{ * [self layoutIfNeeded]; * }]; */ } //重置約束 - (void)updateConstraints { [self.btn remakeConstraints:^(MASConstraintMaker *make) { ..... }]; [super updateConstraints]; } + (BOOL)requiresConstraintBasedLayout{ return YES ; //重寫這個方法 若視圖基於自動佈局的 }
首先介紹2個函數
/** * axisType 軸線方向 * fixedSpacing 間隔大小 * fixedItemLength 每一個控件的固定長度/寬度 * leadSpacing 頭部間隔 * tailSpacing 尾部間隔 * */ //1. 等間隔排列 - 多個控件間隔固定,控件長度/寬度變化 - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing; //2. 等間隔排列 - 多個固定大小固定,間隔空隙變化 - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
//首先添加5個視圖 NSMutableArray *array = [NSMutableArray new]; for (int i = 0; i < 5; i ++) { UIView *view = [UIView new]; view.backgroundColor = [UIColor greenColor]; [self addSubview:view]; [array addObject:view]; //保存添加的控件 } //水平方向控件間隔固定等間隔 [array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:15 leadSpacing:10 tailSpacing:10]; [array makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(50); make.height.equalTo(70); }]; //水平方向寬度固定等間隔 [array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:70 leadSpacing:10 tailSpacing:10]; [array makeConstraints:^(MASConstraintMaker *make) { //數組額你沒必要須都是view make.top.equalTo(50); make.height.equalTo(70); }];
水平方向等間隔.png
水平方向控件寬度固定等間隔.png
對於UILabel
文字內容多的問題,我的以爲Masonry
約束設置的很是簡單優雅,在此很是感謝Masonry
的做者@Robert Payne
//建立label self.label = [UILabel new]; self.label.numberOfLines = 0; self.label.lineBreakMode = NSLineBreakByTruncatingTail; self.label.text = @"有的人,沒事時喜歡在朋友圈裏處處點贊,東評論一句西評論一句,比誰都有存在感。等你有事找他了,他就馬上變得很忙,讓你再也找不着。真正的朋友,日常不多聯繫。可一旦你趕上了難處,他會馬上回復你的消息,第一時間站出來幫你。所謂的存在感,不是你有沒有出現,而是你的出現有沒有價值。存在感,不是刷出來的,也不是說出來的。有存在感,未必是要個性鋒芒畢露、甚至鋒利扎人。翩翩君子,溫潤如玉,真正有存在感的人,反而不會刻意去強調他的存在感。他的出現,永遠都恰到好處。我所欣賞的存在感,不是長袖善舞巧言令色,而是對他人的真心關照;不是鋒芒畢露計較勝負,而是讓人相處得舒服;不是時時刻刻聒噪不休,而是關鍵時刻能自告奮勇。別總急着出風頭,但願你能有恰到好處的存在感。"; [self addSubview: self.label]; [self.label makeConstraints:^(MASConstraintMaker *make) { make.left.top.equalTo(10); make.right.equalTo(-10); }]; //添加約束 - (void)layoutSubviews { //1. 執行 [super layoutSubviews]; [super layoutSubviews]; //2. 設置preferredMaxLayoutWidth: 多行label約束的完美解決 self.label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20; //3. 設置preferredLayoutWidth後,須要再次執行 [super layoutSubviews]; //其實在實際中這步不寫,也不會出錯,官方解釋是說設置preferredLayoutWidth後須要從新計算並佈局界面,因此這步最好執行 [super layoutSubviews]; }
多行label約束.png
原理同自動佈局同樣 UIScrollView上添加UIView
UIView上添加須要顯示的控件 UIScrollView滾動高度取決於顯示控件的總高度
對子控件作好約束,可達到控制UIView的大小
//建立滾動視圖 UIScrollView *scrollView = [UIScrollView new]; self.scrollView = scrollView; scrollView.backgroundColor = [UIColor grayColor]; [self addSubview:scrollView]; [self.scrollView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; [self setUpContentView]; //添加內容視圖 - (void)setUpContentView { //約束UIScrollView上contentView UIView *contentView = [UIView new]; [self.scrollView addSubview:contentView]; [contentView makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.scrollView); make.width.equalTo(self.scrollView); //此處必填 - 關鍵點 }]; //添加控件到contentView,約束原理與自動佈局相同 UIView *lastView; CGFloat height = 30; for (int i = 0; i <1 5; i ++) { UIView *view = UIView.new; view.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 256.0 green:arc4random() % 255 / 256.0 blue:arc4random() % 255 / 256.0 alpha:1.0]; [contentView addSubview:view]; [view makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(lastView ? lastView.bottom : @0); make.left.equalTo(0); make.width.equalTo(contentView.width); make.height.equalTo(height); }]; height += 30; lastView = view; } [contentView makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(lastView.bottom); }]; }