iOS自動(dòng)布局框架 - Masonry詳解

本文章轉(zhuǎn)自http://www.itdecent.cn/p/428783e1e47e,學(xué)習(xí)使用

1. 概念

iOS通過純代碼進(jìn)行UI開發(fā)的話,屏幕適配有時(shí)會(huì)比較麻煩,所以一般都會(huì)使用 自動(dòng)化布局框架 進(jìn)行屏幕適配工作,其中 Masonry 是一種非常流行的第三方布局框架。

2. 基礎(chǔ)知識(shí)

(1) 設(shè)置約束方法

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

綜述:
make用第一次添加的, update用最新的, remake不但用最新的,同時(shí)還會(huì)把原有的統(tǒng)統(tǒng)刪除,不管是不是同類約束

注意:

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

(2) 相關(guān)屬性

@property (nonatomic, strong, readonly) MASConstraint *left; // 左側(cè)
@property (nonatomic, strong, readonly) MASConstraint *top; // 上側(cè)
@property (nonatomic, strong, readonly) MASConstraint *right; // 右側(cè)
@property (nonatomic, strong, readonly) MASConstraint *bottom; // 下冊(cè)
@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; // 橫向中點(diǎn)
@property (nonatomic, strong, readonly) MASConstraint *centerY; // 縱向中點(diǎn)
@property (nonatomic, strong, readonly) MASConstraint *baseline; // 文本基線

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

(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:支持類型轉(zhuǎn)換,支持復(fù)雜類型,是對(duì)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文件中即可:

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

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

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

(5) 約束比例

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

3. 使用技巧

(1) 多行顯示

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

self.textLabel.text = @"蒹葭蒼蒼,白露為霜。所謂伊人,在水一方。溯洄從之,道阻且長。溯游從之,宛在水中央。蒹葭萋萋,白露未晞。所謂伊人,在水之湄。溯洄從之,道阻且躋。溯游從之,宛在水中坻。";

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

(2) 設(shè)置內(nèi)邊距

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

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

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

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

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

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

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self.view addSubview:self.firstView];
    // 設(shè)置約束
    [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));
    }];
    
    // 告訴約束需要更新,但不會(huì)立即更新,
    //[self.firstView.superview setNeedsUpdateConstraints];
    [self.view setNeedsUpdateConstraints];
    // 檢測當(dāng)前視圖及其子視圖是否需要更新約束
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.4 animations:^{
        // 立即更新約束
        [self.view layoutIfNeeded];
    }];
}

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

// 創(chuàng)建一個(gè)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動(dòng)態(tài)Cell高度

原理:

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

// 2. 對(duì)自定義Cell里面的控件,要設(shè)置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) {
        // 設(shè)置邊距相對(duì)于scrollView的約束
        make.edges.equalTo(scrollView);
        // 設(shè)置寬度
        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) {
        // 設(shè)置contentView的底部約束等于最后一個(gè)視圖底部約束
        make.bottom.equalTo(lastView.mas_bottom);
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容