Masonry簡(jiǎn)介
Masonry
是一個(gè)輕量級(jí)的布局框架瓦盛,它擁有自己的描述語(yǔ)法(采用更優(yōu)雅的鏈?zhǔn)秸Z(yǔ)法封裝)來(lái)自動(dòng)布局贷腕,具有很好可讀性且同時(shí)支持iOS和Max OS X
等。
總之蔓涧,對(duì)于側(cè)重寫代碼的coder构灸,請(qǐng)你慢慢忘記Frame
上渴,喜歡Masonry
吧
使用前的準(zhǔn)備
若是你對(duì)于自動(dòng)布局很熟練的話,再接觸這個(gè)第三方
Masonry
很容易上手的喜颁,對(duì)UI界面顯示的控件的約束本質(zhì)都是相同的稠氮,現(xiàn)在呢,我一般都是喜歡在控制器里導(dǎo)入#import "Masonry.h"
之前再添加兩個(gè)宏半开,來(lái)提高App的開發(fā)效率括袒。
//1. 對(duì)于約束參數(shù)可以省去"mas_"
#define MAS_SHORTHAND
//2. 對(duì)于默認(rèn)的約束參數(shù)自動(dòng)裝箱
#define MAS_SHORTHAND_GLOBALS
即:需要我們導(dǎo)入的框架與宏如下
//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" //宏必須添加在頭文件前面
添加約束前提:被約束的必須有父控件,其中約束項(xiàng)都必須是
UIView或子類的實(shí)例
。
約束的屬性
在此我就列舉幾個(gè)可能不太熟悉的吧
@property (nonatomic, strong, readonly) MASConstraint *leading; //首部
@property (nonatomic, strong, readonly) MASConstraint *trailing; //尾部
@property (nonatomic, strong, readonly) MASConstraint *baseline; //文本基線
約束的三種方法
/**
//這個(gè)方法只會(huì)添加新的約束
[blueView mas_makeConstraints:^(MASConstraintMaker *make) {
}];
// 這個(gè)方法會(huì)將以前的所有約束刪掉稿茉,添加新的約束
[blueView mas_remakeConstraints:^(MASConstraintMaker *make) {
}];
// 這個(gè)方法將會(huì)覆蓋以前的某些特定的約束
[blueView mas_updateConstraints:^(MASConstraintMaker *make) {
}];
*/
常見約束的各種類型
/**
1.尺寸:width、height芥炭、size
2.邊界:left漓库、leading、right园蝠、trailing渺蒿、top、bottom
3.中心點(diǎn):center彪薛、centerX茂装、centerY
4.邊界:edges
5.偏移量:offset、insets善延、sizeOffset少态、centerOffset
6.priority()約束優(yōu)先級(jí)(0~1000),multipler乘因數(shù), dividedBy除因數(shù)
*/
Masonry約束易忽略的技術(shù)點(diǎn)
使用
Masonry
不需要設(shè)置控件的translatesAutoresizingMaskIntoConstraints
屬性為NO
;
防止block
中的循環(huán)引用易遣,使用弱引用(這是錯(cuò)誤觀點(diǎn))彼妻,在這里block
是局部的引用,block
內(nèi)部引用self
不會(huì)造成循環(huán)引用的
__weak typeof (self) weakSelf = self
;(沒必要的寫法)
Masonry約束控件出現(xiàn)沖突的問(wèn)題
當(dāng)約束沖突發(fā)生的時(shí)候豆茫,我們可以設(shè)置view的key來(lái)定位是哪個(gè)view
1. 挨個(gè)設(shè)置對(duì)應(yīng)的key
redView.mas_key = @"redView";
greenView.mas_key = @"greenView";
2. 使用Masonry提供的宏 MASAttachKeys
MASAttachKeys(redView);
MASAttachKeys(redView,greenView); // 可批量設(shè)置
約束iconView
距離各個(gè)邊距為30
[iconView makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(30, 30, 30, 30));
}];
equalTo 和 mas_equalTo的區(qū)別
#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__)))
得出結(jié)論:mas_equalTo
只是對(duì)其參數(shù)進(jìn)行了一個(gè)BOX
(裝箱) 操作侨歉,目前支持的類型:數(shù)值類型(NSNumber)、 點(diǎn)(CGPoint)揩魂、大杏牡恕(CGSize)、邊距(UIEdgeInsets)
火脉,而equalTo:
這個(gè)方法不會(huì)對(duì)參數(shù)進(jìn)行包裝牵舵。
//常見約束的寫法
[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 增強(qiáng)可讀性
make.left.equalTo(greenView.mas_right).and.offset(10); //and 增強(qiáng)可讀性
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]); //約束參數(shù)相同可以通過(guò)數(shù)組
}];
更新約束的問(wèn)題
例如:控制器有個(gè)按鈕柒啤,若是點(diǎn)擊按鈕,則按鈕本身的大小棋枕、位置會(huì)隨機(jī)改變
- 監(jiān)聽按鈕點(diǎn)擊
[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); //設(shè)置一個(gè)屬性(btnSize)保存其大小的變化
//1.告知需要更新約束白修,但不會(huì)立刻開始,系統(tǒng)然后調(diào)用updateConstraints
[self setNeedsUpdateConstraints];
//2.告知立刻更新約束重斑,系統(tǒng)立即調(diào)用updateConstraints
[self updateConstraintsIfNeeded];
//3.這里動(dòng)畫當(dāng)然可以取消兵睛,具體看項(xiàng)目的需求
//系統(tǒng)block內(nèi)引用不會(huì)導(dǎo)致循環(huán)引用,block結(jié)束就會(huì)釋放引用對(duì)象
[UIView animateWithDuration:0.4 animations:^{
[self layoutIfNeeded]; //告知頁(yè)面立刻刷新窥浪,系統(tǒng)立即調(diào)用updateConstraints
}];
}
- 蘋果官方建議:添加/更新約束在這個(gè)方法
(updateConstraints)
內(nèi)
// 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
//最后必須調(diào)用父類的更新約束
[super updateConstraints];
}
- 設(shè)置
requiresConstraintBasedLayout
為YES
+ (BOOL)requiresConstraintBasedLayout{
return YES ; //重寫這個(gè)方法 若視圖基于自動(dòng)布局的
}
重置約束的問(wèn)題
對(duì)于控件的重新約束祖很,則之前的約束都是無(wú)效的,步驟都更新約束一樣的漾脂,只是在updateConstraints
方法內(nèi)的約束方法改為了remakeConstraints
//首先監(jiān)聽按鈕
[self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
//處理事件
- (void) didClickBtn :(UIButton *)button{
(...) //觸發(fā)條件
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
/**
* 動(dòng)畫展示變化 - 這句代碼可有可無(wú)假颇,參考項(xiàng)目具體的需求
* [UIView animateWithDuration:0.4 animations:^{
* [self layoutIfNeeded];
* }];
*/
}
//重置約束
- (void)updateConstraints {
[self.btn remakeConstraints:^(MASConstraintMaker *make) {
.....
}];
[super updateConstraints];
}
+ (BOOL)requiresConstraintBasedLayout{
return YES ; //重寫這個(gè)方法 若視圖基于自動(dòng)布局的
}
多個(gè)(2個(gè)以上)控件的等間隔排序顯示
首先介紹2個(gè)函數(shù)
/**
* 等間隔排列 - 多個(gè)控件間隔固定,控件長(zhǎng)度/寬度變化
* axisType 軸線方向 橫排還是豎排
* fixedSpacing 間隔大小 兩個(gè)控件間隔
* leadSpacing 頭部間隔 第一個(gè)控件與邊緣的間隔
* tailSpacing 尾部間隔 最后一個(gè)控件與邊緣的間隔
*
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing
tailSpacing:(CGFloat)tailSpacing;
/**
* 等間隔排列 - 多個(gè)固定大小固定骨稿,間隔空隙變化
* axisType 軸線方向 橫排還是豎排
* withFixedItemLength 控件的寬或高
* leadSpacing 頭部間隔 第一個(gè)控件與邊緣的間隔
* tailSpacing 尾部間隔 最后一個(gè)控件與邊緣的間隔
*
*/
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
withFixedItemLength:(CGFloat)fixedItemLength
leadSpacing:(CGFloat)leadSpacing
tailSpacing:(CGFloat)tailSpacing;
- 設(shè)置水平方向MASAxisTypeHorizontal 若是指定控件的寬withFixedItemLength, 則對(duì)應(yīng)控件只需要設(shè)置其Y軸位置; 若是指定控件的間隔fixedSpacing, 則對(duì)應(yīng)控件需要設(shè)置其Y軸和對(duì)應(yīng)的高度H
- 設(shè)置垂直方向MASAxisTypeVertical 若是指定控件的高withFixedItemLength, 則對(duì)應(yīng)控件只需要設(shè)置其X軸位置; 若是指定控件的間隔fixedSpacing, 則對(duì)應(yīng)控件需要設(shè)置其X軸和對(duì)應(yīng)的寬度W
//首先添加5個(gè)視圖
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);
// make.bottom.equalTo(self);
}];
//水平方向?qū)挾裙潭ǖ乳g隔
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:70 leadSpacing:10 tailSpacing:10];
[array makeConstraints:^(MASConstraintMaker *make) { //數(shù)組額你不必須都是view
make.top.equalTo(50);
}];
多行l(wèi)abel的約束問(wèn)題
對(duì)于UILabel
文字內(nèi)容多的問(wèn)題笨鸡,個(gè)人覺得Masonry
約束設(shè)置的非常簡(jiǎn)單優(yōu)雅,在此非常感謝Masonry
的作者@Robert Payne
//創(chuàng)建label
self.label = [UILabel new];
self.label.numberOfLines = 0;
self.label.lineBreakMode = NSLineBreakByTruncatingTail;
self.label.text = @"有的人坦冠,沒事時(shí)喜歡在朋友圈里到處點(diǎn)贊形耗,東評(píng)論一句西評(píng)論一句,比誰(shuí)都有存在感辙浑。等你有事找他了激涤,他就立刻變得很忙,讓你再也找不著判呕。真正的朋友倦踢,平常很少聯(lián)系∠啦荩可一旦你遇上了難處辱挥,他會(huì)立刻回復(fù)你的消息,第一時(shí)間站出來(lái)幫你边涕。所謂的存在感般贼,不是你有沒有出現(xiàn),而是你的出現(xiàn)有沒有價(jià)值奥吩。存在感哼蛆,不是刷出來(lái)的,也不是說(shuō)出來(lái)的霞赫。有存在感腮介,未必是要個(gè)性鋒芒畢露、甚至鋒利扎人端衰。翩翩君子叠洗,溫潤(rùn)如玉甘改,真正有存在感的人,反而不會(huì)刻意去強(qiáng)調(diào)他的存在感灭抑。他的出現(xiàn)十艾,永遠(yuǎn)都恰到好處。我所欣賞的存在感腾节,不是長(zhǎng)袖善舞巧言令色忘嫉,而是對(duì)他人的真心關(guān)照;不是鋒芒畢露計(jì)較勝負(fù)案腺,而是讓人相處得舒服庆冕;不是時(shí)時(shí)刻刻聒噪不休,而是關(guān)鍵時(shí)刻能挺身而出劈榨。別總急著出風(fēng)頭访递,希望你能有恰到好處的存在感。";
[self addSubview: self.label];
[self.label makeConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(10);
make.right.equalTo(-10);
}];
//添加約束
- (void)layoutSubviews {
//1. 執(zhí)行 [super layoutSubviews];
[super layoutSubviews];
//2. 設(shè)置preferredMaxLayoutWidth: 多行l(wèi)abel約束的完美解決
self.label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
//3. 設(shè)置preferredLayoutWidth后同辣,需要再次執(zhí)行 [super layoutSubviews];
//其實(shí)在實(shí)際中這步不寫拷姿,也不會(huì)出錯(cuò),官方解釋是說(shuō)設(shè)置preferredLayoutWidth后需要重新計(jì)算并布局界面旱函,所以這步最好執(zhí)行
[super layoutSubviews];
}
UIScrollView的問(wèn)題
原理同自動(dòng)布局一樣 UIScrollView上添加UIView
UIView上添加需要顯示的控件 UIScrollView滾動(dòng)高度取決于顯示控件的總高度
對(duì)子控件做好約束跌前,可達(dá)到控制UIView的大小
//創(chuàng)建滾動(dòng)視圖
UIScrollView *scrollView = [UIScrollView new];
self.scrollView = scrollView;
scrollView.backgroundColor = [UIColor grayColor];
[self addSubview:scrollView];
[self.scrollView makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
[self configUpContentView]; //添加內(nèi)容視圖
- (void)configUpContentView {
UIView *container = [UIView new];
[self.scrollView addSubview:container];
[container makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.scrollView);
make.width.equalTo(self.scrollView); //此處必填 - 關(guān)鍵點(diǎn)
}];
//添加控件到contentView,約束原理與自動(dòng)布局相同
UIView *lastView = nil;
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);
}];
}
Masonry
源碼GitHub
地址下載:Masonry
終于寫完了陡舅,有什么理解不對(duì)的直接說(shuō)...今晚還有巴薩、尤文的歐冠伴挚,真心傷不起靶衍。。茎芋。