iOS自動布局框架 - Masonry詳解

本文章轉自http://www.reibang.com/p/428783e1e47e贡定,學習使用

1. 概念

iOS通過純代碼進行UI開發(fā)的話怎顾,屏幕適配有時會比較麻煩盐类,所以一般都會使用 自動化布局框架 進行屏幕適配工作恤浪,其中 Masonry 是一種非常流行的第三方布局框架。

2. 基礎知識

(1) 設置約束方法

// 添加約束
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
// 更新約束揩晴,更新修改的約束筐钟,在原有的約束基礎上更新同類約束,其他約束不變
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
// 移除約束疹鳄,并重新添加約束 
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

綜述:
make用第一次添加的拧略, update用最新的, remake不但用最新的瘪弓,同時還會把原有的統(tǒng)統(tǒng)刪除垫蛆,不管是不是同類約束

注意:

  • 使用 Masonry 添加約束之前,需要在 addSubview之后 才能生效。

(2) 相關屬性

@property (nonatomic, strong, readonly) MASConstraint *left; // 左側
@property (nonatomic, strong, readonly) MASConstraint *top; // 上側
@property (nonatomic, strong, readonly) MASConstraint *right; // 右側
@property (nonatomic, strong, readonly) MASConstraint *bottom; // 下冊
@property (nonatomic, strong, readonly) MASConstraint *leading; // 首部
@property (nonatomic, strong, readonly) MASConstraint *trailing; // 尾部
@property (nonatomic, strong, readonly) MASConstraint *width; // 寬
@property (nonatomic, strong, readonly) MASConstraint *height; // 高
@property (nonatomic, strong, readonly) MASConstraint *centerX; // 橫向中點
@property (nonatomic, strong, readonly) MASConstraint *centerY; // 縱向中點
@property (nonatomic, strong, readonly) MASConstraint *baseline; // 文本基線

@property (nonatomic, strong, readonly) MASConstraint *edges; // 內邊距
@property (nonatomic, strong, readonly) MASConstraint *size; // 尺寸
@property (nonatomic, strong, readonly) MASConstraint *center; // 中點

(3) 常用方法

// 等于
- (MASConstraint * (^)(id attr))equalTo;
- (MASConstraint * (^)(id attr))mas_equalTo;
// 大于等于
- (MASConstraint * (^)(id attr))greaterThanOrEqualTo;
- (MASConstraint * (^)(id attr))mas_greaterThanOrEqualTo;
// 小于等于
- (MASConstraint * (^)(id attr))lessThanOrEqualTo;
- (MASConstraint * (^)(id attr))mas_lessThanOrEqualTo;
// 偏移量
- (MASConstraint * (^)(CGFloat offset))offset;
- (MASConstraint * (^)(id offset))mas_offset;
1> 方法區(qū)別
  • equalTo:僅支持基本類型袱饭;
  • mas_equalTo:支持類型轉換川无,支持復雜類型,是對equalTo的封裝虑乖;
    支持CGSize懦趋、CGPointNSNumber决左、UlEdgeinsets愕够。
    例如:
make.width.equalTo(@100); 等同于 
make.width.mas_equalTo(100);

make.bottom.equalTo(self.view); 等同于
make.bottom.mas_equalTo(self.view.mas_bottom);
2> 簡化方法

想要去掉mas_前綴,只用equalTo佛猛,將一下代碼添加到.prefix文件中即可:

// 添加這個宏惑芭,就不用帶mas_前綴
#define MAS SHORTHAND
// 添加這個宏,equalTo就等價于mas_equalTo
#define MAS SHORTHAND GLOBALS
// 此頭文件一定要放在上面兩個宏的后面才可生效
#import "Masonry.h"

(4) 約束優(yōu)先級

// 設置優(yōu)先級
- (MASConstraint * (^)(MASLayoutPriority priority))priority;
// 優(yōu)先級低
- (MASConstraint * (^)(void))priorityLow;
// 優(yōu)先級中
- (MASConstraint * (^)(void))priorityMedium;
// 優(yōu)先級高
- (MASConstraint * (^)(void))priorityHigh;

(5) 約束比例

// 約束值為約束對象的乘因數(shù) 即 倍數(shù)
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;
// 表示約束值為約束對象的除因數(shù) 即 比例
- (MASConstraint * (^)(CGFloat divider))dividedBy;

3. 使用技巧

(1) 多行顯示

// 首先addSubview
[self.view addSubview:self.textLabel];
// 設置約束
[self.textLabel mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    // 設置寬度 小于等于300
    make.width.mas_lessThanOrEqualTo(300);
    // 設置高度 大于等于20
    make.height.mas_greaterThanOrEqualTo(20);
}];

self.textLabel.text = @"蒹葭蒼蒼继找,白露為霜遂跟。所謂伊人,在水一方婴渡。溯洄從之幻锁,道阻且長。溯游從之边臼,宛在水中央哄尔。蒹葭萋萋,白露未晞柠并。所謂伊人岭接,在水之湄声怔。溯洄從之忙芒,道阻且躋。溯游從之昧廷,宛在水中坻粘拾。";

// 1. 設置多行顯示
self.textLabel.numberOfLines = 0;
// 2. 設置最大寬度
self.textLabel.preferredMaxLayoutWidth = 300;
// 3. 設置UILayout優(yōu)先級及軸向
[self.textLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];

(2) 設置內邊距

[self.view addSubview:self.firstView];
[self.firstView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.left.equalTo(self.view).offset(10);
    // 注意根據(jù)UIView的坐標系窄锅,right和bottom進行取反。
    make.bottom.right.mas_equalTo(-10);
}];

[self.firstView mas_makeConstraints:^(MASConstraintMaker *make) {
    // insets方法自動做出取反操作
    make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];

(3) 多個控件等間隔排序

/**
 *  多個控件固定間隔的等間隔排列缰雇,變化的是控件的長度或者寬度值
 *
 *  @param axisType        軸線方向
 *  @param fixedSpacing    間隔大小
 *  @param leadSpacing     頭部間隔
 *  @param tailSpacing     尾部間隔
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
                    withFixedSpacing:(CGFloat)fixedSpacing
                         leadSpacing:(CGFloat)leadSpacing
                         tailSpacing:(CGFloat)tailSpacing;

/**
 *  多個固定大小的控件的等間隔排列,變化的是間隔的空隙
 *
 *  @param axisType        軸線方向
 *  @param fixedItemLength 每個控件的固定長度或者寬度值
 *  @param leadSpacing     頭部間隔
 *  @param tailSpacing     尾部間隔
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType
                 withFixedItemLength:(CGFloat)fixedItemLength
                         leadSpacing:(CGFloat)leadSpacing
                         tailSpacing:(CGFloat)tailSpacing;

(4) 更新約束之后動畫效果

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self.view addSubview:self.firstView];
    // 設置約束
    [self.firstView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.height.mas_equalTo(100);
    }];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // 更新約束
    [self.firstView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(10, 10, 10, 10));
    }];
    
    // 告訴約束需要更新入偷,但不會立即更新,
    //[self.firstView.superview setNeedsUpdateConstraints];
    [self.view setNeedsUpdateConstraints];
    // 檢測當前視圖及其子視圖是否需要更新約束
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.4 animations:^{
        // 立即更新約束
        [self.view layoutIfNeeded];
    }];
}

(5) For循環(huán)創(chuàng)建多個控件

// 創(chuàng)建一個View作為容器
UIView *lastView = [[UIView alloc] init];
[self.view addSubview:lastView];
[lastView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(15, 15, 15,15));
}];

for (int i = 0; i < 10; i++) {
    // 創(chuàng)建新的view
    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [self randomColor];
    [lastView addSubview:view];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(lastView).insets(UIEdgeInsetsMake(15, 15, 15,15));
    }];
    
    // 將view賦值給lastView
    lastView = view;
}

(6) UITableView動態(tài)Cell高度

原理:

  • 對tableView設置預估高度械哟;
  • 對自定義Cell里面的控件盯串,要設置cell里最上方控件與cell.contentView上方的距離,最下方控件與cell.contentView下方的距離戒良。
// 1. 對tableView設置預估高度体捏;
- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        // 設置預估高度
        _tableView.estimatedRowHeight = 50;
    }
    return _tableView;
}

// 2. 對自定義Cell里面的控件,要設置cell里最上方控件與cell.contentView上方的距離,最下方控件與cell.contentView下方的距離几缭。
- (void)settingUI {
    [self.contentView addSubview:self.detailLabel];
    [self.detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.contentView).insets(UIEdgeInsetsMake(15, 15, 15, 15));
    }];
}

(7) scrollView使用約束的問題

原理:給scrollView添加唯一的子視圖contentView河泳,通過拉伸子視圖的size來確定scrollViewcontentSize

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // 創(chuàng)建scrollView
    UIScrollView *scrollView = [[UIScrollView alloc] init];;
    scrollView.backgroundColor = [UIColor redColor];
    [self.view addSubview:scrollView];
    [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    // 創(chuàng)建contentView年栓,添加到scrollView作為唯一子視圖
    UIView *contentView = [[UIView alloc] init];
    contentView.backgroundColor = [UIColor whiteColor];
    [scrollView addSubview:contentView];
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        // 設置邊距相對于scrollView的約束
        make.edges.equalTo(scrollView);
        // 設置寬度
        make.width.equalTo(scrollView);
    }];
    
    UIView *lastView;
    
    for (NSInteger i = 0; i < 10; i++) {
        UIView *view = [UIView new];
        view.backgroundColor = [self randomColor];
        [contentView addSubview:view];
        [view mas_makeConstraints:^(MASConstraintMaker *make) {
            if (i == 0) {
                make.top.equalTo(contentView);
            } else {
                make.top.equalTo(lastView.mas_bottom).offset(10);
            }
            make.left.right.equalTo(contentView);
            make.height.mas_equalTo(100);
        }];

        lastView = view;
    }
    
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        // 設置contentView的底部約束等于最后一個視圖底部約束
        make.bottom.equalTo(lastView.mas_bottom);
    }];
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末拆挥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子某抓,更是在濱河造成了極大的恐慌纸兔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件否副,死亡現(xiàn)場離奇詭異汉矿,居然都是意外死亡,警方通過查閱死者的電腦和手機备禀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門洲拇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人曲尸,你說我怎么就攤上這事赋续。” “怎么了另患?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵纽乱,是天一觀的道長。 經(jīng)常有香客問我昆箕,道長鸦列,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任为严,我火速辦了婚禮敛熬,結果婚禮上肺稀,老公的妹妹穿的比我還像新娘第股。我一直安慰自己,他們只是感情好话原,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布夕吻。 她就那樣靜靜地躺著,像睡著了一般繁仁。 火紅的嫁衣襯著肌膚如雪涉馅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天黄虱,我揣著相機與錄音稚矿,去河邊找鬼。 笑死,一個胖子當著我的面吹牛晤揣,可吹牛的內容都是我干的桥爽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昧识,長吁一口氣:“原來是場噩夢啊……” “哼钠四!你這毒婦竟也來了?” 一聲冷哼從身側響起跪楞,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤缀去,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后甸祭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缕碎,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年淋叶,在試婚紗的時候發(fā)現(xiàn)自己被綠了阎曹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡煞檩,死狀恐怖处嫌,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情斟湃,我是刑警寧澤熏迹,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站凝赛,受9級特大地震影響注暗,放射性物質發(fā)生泄漏。R本人自食惡果不足惜墓猎,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一捆昏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毙沾,春花似錦骗卜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烤宙,卻和暖如春遍烦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躺枕。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工服猪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留供填,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓罢猪,卻偏偏與公主長得像捕虽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坡脐,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內容