Masonry-1

簡(jiǎn)介

Masonry is still actively maintained, we are committed to fixing bugs and merging good quality PRs from the wider community. However if you're using Swift in your project, we recommend using SnapKit as it provides better type safety with a simpler API.

Masonry 傳送門

使用前的準(zhǔn)備

// 對(duì)于約束參數(shù)可以省去"mas_"
#define MAS_SHORTHAND
// 對(duì)于默認(rèn)的約束參數(shù)自動(dòng)裝箱
#define MAS_SHORTHAND_GLOBALS

直接這樣

// 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è)方法只會(huì)添加新的約束
 [blueView mas_makeConstraints:^(MASConstraintMaker *make)  {

 }];

 // 這個(gè)方法會(huì)將以前的所有約束刪掉,添加新的約束
 [blueView mas_remakeConstraints:^(MASConstraintMaker *make) {

 }];

 // 這個(gè)方法將會(huì)覆蓋以前的某些特定的約束
 [blueView mas_updateConstraints:^(MASConstraintMaker *make) {

 }];
 */

常見約束的各種類型

/**
 尺寸:width袒哥、height枝秤、size
 邊界:left、leading反镇、right赏陵、trailing沉帮、top、bottom
 中心點(diǎn):center珍剑、centerX掸宛、centerY
 邊界:edges
 偏移量:offset、insets招拙、sizeOffset唧瘾、centerOffset
 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)沖突的問題

當(dāng)約束沖突發(fā)生的時(shí)候规哪,我們可以設(shè)置viewkey來定位是哪個(gè)view

redView.mas_key = @"redView";

greenView.mas_key = @"greenView";

blueView.mas_key = @"blueView";

若是覺得這樣一個(gè)個(gè)設(shè)置比較繁瑣求豫,怎么辦呢,Masonry則提供了批量設(shè)置的宏

MASAttachKeys
MASAttachKeys(redView,greenView,blueView);

約束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) {
        // with 增強(qiáng)可讀性
        make.top.equalTo(superview.mas_top).with.offset(10);  
        // and 增強(qiáng)可讀性
        make.left.equalTo(greenView.mas_right).and.offset(10);
        make.bottom.equalTo(blueView.mas_top).offset(-10);
        make.right.equalTo(superview.mas_right).offset(-10);
        make.width.equalTo(greenView.mas_width);
        // 約束參數(shù)相同可以通過數(shù)組
        make.height.equalTo(@[greenView, blueView]); 
    }];

更新約束的問題

  • 監(jiān)聽按鈕點(diǎn)擊
[self.btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
  • 處理事件
- (void)didClickBtn:(UIButton *)button {
  // 設(shè)置一個(gè)屬性(btnSize)保存其大小的變化
  self.btnSize = CGSizeMake(self.btnSize.width * 1.3, self.btnSize.height * 1.3); 
  // 告知需要更新約束杜恰,但不會(huì)立刻開始获诈,系統(tǒng)然后調(diào)用updateConstraints
  [self setNeedsUpdateConstraints];
  // 告知立刻更新約束,系統(tǒng)立即調(diào)用updateConstraints
  [self updateConstraintsIfNeeded];
  // 這里動(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:^{
      // 告知頁面立刻刷新,系統(tǒng)立即調(diào)用updateConstraints
      [self layoutIfNeeded]; 
  }];
}
  • 蘋果官方建議:添加/更新約束在這個(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 {
    // 重寫這個(gè)方法 若視圖基于自動(dòng)布局的
    return YES ; 
}

重置約束的問題

對(duì)于控件的重新約束檬寂,則之前的約束都是無效的终抽,步驟都更新約束一樣的,只是在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)畫展示變化 - 這句代碼可有可無,參考項(xiàng)目具體的需求
     *   [UIView animateWithDuration:0.4 animations:^{
     *         [self layoutIfNeeded];
     *   }];
     */
}

// 重置約束
- (void)updateConstraints {
    [self.btn remakeConstraints:^(MASConstraintMaker *make) {
      .....
    }];
    [super updateConstraints]; 
}

+ (BOOL)requiresConstraintBasedLayout{
    // 重寫這個(gè)方法 若視圖基于自動(dòng)布局的
    return YES ; 
}

多個(gè)(2個(gè)以上)控件的等間隔排序顯示

2個(gè)函數(shù)

/**
     *  axisType         軸線方向
     *  fixedSpacing     間隔大小
     *  fixedItemLength  每個(gè)控件的固定長(zhǎng)度/寬度
     *  leadSpacing      頭部間隔
     *  tailSpacing      尾部間隔
     *
     */
// 等間隔排列 - 多個(gè)控件間隔固定镣屹,控件長(zhǎng)度/寬度變化
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
                    withFixedSpacing:(CGFloat)fixedSpacing 
                         leadSpacing:(CGFloat)leadSpacing
                         tailSpacing:(CGFloat)tailSpacing;

// 等間隔排列 - 多個(gè)固定大小固定圃郊,間隔空隙變化
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
                 withFixedItemLength:(CGFloat)fixedItemLength
                         leadSpacing:(CGFloat)leadSpacing
                         tailSpacing:(CGFloat)tailSpacing;
// 首先添加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);
            }];

// 水平方向?qū)挾裙潭ǖ乳g隔
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:70 leadSpacing:10 tailSpacing:10];
            [array makeConstraints:^(MASConstraintMaker *make) { 
                // 數(shù)組額你不必須都是view 
                make.top.equalTo(50);
                make.height.equalTo(70);
            }];
水平方向等間隔.png
水平方向控件寬度固定等間隔.png

多行l(wèi)abel的約束問題

// 創(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)論一句持舆,比誰都有存在感。等你有事找他了伪窖,他就立刻變得很忙逸寓,讓你再也找不著。真正的朋友覆山,平常很少聯(lián)系竹伸。可一旦你遇上了難處簇宽,他會(huì)立刻回復(fù)你的消息勋篓,第一時(shí)間站出來幫你。所謂的存在感魏割,不是你有沒有出現(xiàn)譬嚣,而是你的出現(xiàn)有沒有價(jià)值。存在感钞它,不是刷出來的拜银,也不是說出來的。有存在感须揣,未必是要個(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 {
    // 執(zhí)行 [super layoutSubviews];
    [super layoutSubviews];
    // 設(shè)置preferredMaxLayoutWidth: 多行l(wèi)abel約束的完美解決
   self.label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
    // 設(shè)置preferredLayoutWidth后,需要再次執(zhí)行 [super layoutSubviews]; 
    // 其實(shí)在實(shí)際中這步不寫麸折,也不會(huì)出錯(cuò)锡凝,官方解釋是說設(shè)置preferredLayoutWidth后需要重新計(jì)算并布局界面,所以這步最好執(zhí)行
    [super layoutSubviews];
}
多行l(wèi)abel約束.png

UIScrollView

原理同自動(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);
    }];
    // 添加內(nèi)容視圖
    [self setUpContentView]; 

- (void)setUpContentView {
    // 約束UIScrollView上contentView
    UIView *contentView = [UIView new];
    [self.scrollView addSubview:contentView];

    [contentView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.scrollView);
        // 此處必填 - 關(guān)鍵點(diǎn)
        make.width.equalTo(self.scrollView); 
    }];

    // 添加控件到contentView窜锯,約束原理與自動(dòng)布局相同
    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);
    }];
}
scrollView的約束設(shè)置.png

原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芭析,隨后出現(xiàn)的幾起案子锚扎,更是在濱河造成了極大的恐慌,老刑警劉巖放刨,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件工秩,死亡現(xiàn)場(chǎng)離奇詭異尸饺,居然都是意外死亡进统,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門浪听,熙熙樓的掌柜王于貴愁眉苦臉地迎上來螟碎,“玉大人,你說我怎么就攤上這事迹栓〉舴郑” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵克伊,是天一觀的道長(zhǎng)酥郭。 經(jīng)常有香客問我,道長(zhǎng)愿吹,這世上最難降的妖魔是什么不从? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮犁跪,結(jié)果婚禮上椿息,老公的妹妹穿的比我還像新娘歹袁。我一直安慰自己,他們只是感情好寝优,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布条舔。 她就那樣靜靜地躺著,像睡著了一般乏矾。 火紅的嫁衣襯著肌膚如雪孟抗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天钻心,我揣著相機(jī)與錄音夸浅,去河邊找鬼。 笑死扔役,一個(gè)胖子當(dāng)著我的面吹牛帆喇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亿胸,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坯钦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了侈玄?” 一聲冷哼從身側(cè)響起婉刀,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎序仙,沒想到半個(gè)月后突颊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡潘悼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年律秃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片治唤。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棒动,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宾添,到底是詐尸還是另有隱情船惨,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布缕陕,位于F島的核電站粱锐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扛邑。R本人自食惡果不足惜怜浅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹿榜。 院中可真熱鬧海雪,春花似錦锦爵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至湾宙,卻和暖如春樟氢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侠鳄。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工埠啃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伟恶。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓碴开,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親博秫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子潦牛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容