masonry 使用筆記

為什么要做這個(gè)筆記

masonry 可以說(shuō)是當(dāng)前 iOS開(kāi)發(fā)中最流行的 Autolayout框架,其極大的簡(jiǎn)化了蘋(píng)果原生提供的AutoLayout語(yǔ)法。目前很多大廠也是用的這個(gè)自動(dòng)布局框架,我司也在用。在此之前我一只在用另一個(gè)叫 SDAutolayout的自動(dòng)布局庫(kù),所以 masonry 是個(gè)初學(xué)者,如果寫(xiě)得不好的地方還希望大佬指點(diǎn)江山。經(jīng)過(guò)前段時(shí)間的開(kāi)發(fā)項(xiàng)目,對(duì)masonry框架有了大致的認(rèn)識(shí),用法上面基本能解決所有布局問(wèn)題。

masonry 基礎(chǔ)約束用法

  • 首先先提及一下,view 在執(zhí)行 masonry 布局之前必須添加到父視圖上
  • 約束的寫(xiě)法有好幾種,我先拿三種來(lái)舉例
  1. 第一種。mas_equalTo()方法傳入一個(gè)依賴的約束邊,如下面示例中“self.view.mas_left”,后面跟著 mas_offset()方法可以傳入一個(gè)值,這個(gè)值是相對(duì)于所依賴約束的偏移量。mas_offset()也可以不寫(xiě),默認(rèn)偏移0。
    UIView *demoView = [[UIView alloc] init];
    demoView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:demoView];
    [demoView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.view.mas_left).mas_offset(50);//左邊相對(duì)于 self.view 的 left 偏移50個(gè)單位
        make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);//右邊相對(duì)于 self.view 的 right 偏移-50個(gè)單位
        make.top.mas_equalTo(self.view.mas_top).mas_offset(100);//頂邊相對(duì)于 self.view 的 top 偏移100個(gè)單位
        make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);//底邊相對(duì)于 self.view 的 bottom 偏移-100個(gè)單位
    }];
  1. 第二種。mas_equalTo()只需要傳入相對(duì)的約束的視圖,不需要指定約束邊,默認(rèn)取前面第一個(gè)需要添加約束的邊
    UIView *demoView = [[UIView alloc] init];
    demoView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:demoView];
    [demoView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.view).mas_offset(50);//等價(jià)于 make.left.mas_equalTo(self.view.mas_left).mas_offset(50);
        make.right.mas_equalTo(self.view).mas_offset(-50);//等價(jià)于 make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);
        make.top.mas_equalTo(self.view).mas_offset(100);//等價(jià)于 make.top.mas_equalTo(self.view.mas_top).mas_offset(100);
        make.bottom.mas_equalTo(self.view).mas_offset(-100);//等價(jià)于 make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);
    }];
  1. 第三種。mas_equalTo() 傳入一個(gè)值,這個(gè)值就是相對(duì)于依賴父視圖對(duì)應(yīng)相同約束的偏移量
    UIView *demoView = [[UIView alloc] init];
    demoView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:demoView];
    [demoView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(50);//等價(jià)于 make.left.mas_equalTo(demoView.superview.mas_left).mas_offset(50);
        make.right.mas_equalTo(-50);//等價(jià)于 make.right.mas_equalTo(demoView.superview.mas_right).mas_offset(-50);
        make.top.mas_equalTo(100);//等價(jià)于 make.top.mas_equalTo(demoView.superview.mas_top).mas_offset(100);
        make.bottom.mas_equalTo(-100);//等價(jià)于 make.bottom.mas_equalTo(demoView.superview.mas_bottom).mas_offset(-100);
    }];

三種寫(xiě)法結(jié)果是一致的,效果圖如下

WechatIMG38.png

看你個(gè)人喜歡用哪一種,我個(gè)人比較懶,喜歡用第三種,所以都是以第三種寫(xiě)法作為描述

居左上

    YYLabel *leftTopLabel = [[YYLabel alloc] init];
    leftTopLabel.backgroundColor = UIColor.redColor;
    leftTopLabel.text = @"居左上";
    leftTopLabel.textColor = UIColor.whiteColor;
    leftTopLabel.textAlignment = NSTextAlignmentCenter;
    leftTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [demoView addSubview:leftTopLabel];
    [leftTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_offset(0);
        make.top.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];

效果如下

WeChatc5eb1b8916c66b1c53873306fe0597b1.png

居左下

    YYLabel *leftBottomLabel = [[YYLabel alloc] init];
    leftBottomLabel.backgroundColor = UIColor.redColor;
    leftBottomLabel.text = @"居左下";
    leftBottomLabel.textColor = UIColor.whiteColor;
    leftBottomLabel.textAlignment = NSTextAlignmentCenter;
    leftBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [demoView addSubview:leftBottomLabel];
    [leftBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_offset(0);
        make.bottom.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];

效果如下

WeChatb3f1265f09aadcd9e120047158e567cf.png

居右上

    YYLabel *rightTopLabel = [[YYLabel alloc] init];
    rightTopLabel.backgroundColor = UIColor.redColor;
    rightTopLabel.text = @"居右上";
    rightTopLabel.textColor = UIColor.whiteColor;
    rightTopLabel.textAlignment = NSTextAlignmentCenter;
    rightTopLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [demoView addSubview:rightTopLabel];
    [rightTopLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.mas_offset(0);
        make.top.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];
WechatIMG41.jpeg

居右下

    YYLabel *rightBottomLabel = [[YYLabel alloc] init];
    rightBottomLabel.backgroundColor = UIColor.redColor;
    rightBottomLabel.text = @"居右下";
    rightBottomLabel.textColor = UIColor.whiteColor;
    rightBottomLabel.textAlignment = NSTextAlignmentCenter;
    rightBottomLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [demoView addSubview:rightBottomLabel];
    [rightBottomLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.mas_offset(0);
        make.bottom.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];
WechatIMG42.jpeg

垂直水平居中

    YYLabel *centerLabel = [[YYLabel alloc] init];
    centerLabel.backgroundColor = UIColor.redColor;
    centerLabel.text = @"居中";
    centerLabel.textColor = UIColor.whiteColor;
    centerLabel.textAlignment = NSTextAlignmentCenter;
    centerLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [demoView addSubview:centerLabel];
    [centerLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];
WechatIMG43 1.jpeg

子控件來(lái)?yè)纹鸶缚丶母叨?/h2>

平常在開(kāi)發(fā)過(guò)程中,經(jīng)常有這種情況就是父控件高度是根據(jù)子控件內(nèi)容動(dòng)態(tài)變化,用masonry來(lái)實(shí)現(xiàn)這個(gè)功能相當(dāng)簡(jiǎn)單,這里有幾個(gè)知識(shí)點(diǎn);

  1. 約束類對(duì)象MASConstraint,通過(guò)點(diǎn)進(jìn)mas_makeConstraints:方法的實(shí)現(xiàn),源碼如下
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

咋們暫且先不管 MASConstraintMaker 類,找到最后一句constraintMaker對(duì)象調(diào)用了 install 方法并返回;進(jìn)入到這個(gè)install的實(shí)現(xiàn),源碼實(shí)現(xiàn)如下

- (NSArray *)install {
    if (self.removeExisting) {
        NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
        for (MASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    NSArray *constraints = self.constraints.copy;
    for (MASConstraint *constraint in constraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
    [self.constraints removeAllObjects];
    return constraints;
}

其中最上面的那個(gè)判斷條件在調(diào)用mas_remakeConstraints:方法時(shí)會(huì)被執(zhí)行到,咋們也不看。咋們看下面這一段,其實(shí) self.constraints 數(shù)組 就是在mas_makeConstraints:的 block 塊中添加的所有約束對(duì)象,接下來(lái) self.constraints 執(zhí)行 copy 并遍歷執(zhí)行 constraint.updateExisting = self.updateExisting;[constraint install];,for 循環(huán)體中的第一句是標(biāo)記更新約束還是新添加的約束,第二句是對(duì)約束裝載,如果把第二句給注視掉,則添加的所有約束都不會(huì)被添加上,各位可以試一試;在方法的最后 返回了constraints數(shù)組,這個(gè)數(shù)組里面裝的是 MASConstraint 類對(duì)象,再回到上面 mas_makeConstraints:方法中,最后的 return [constraintMaker install];實(shí)際上就是返回另一個(gè)約束對(duì)象的數(shù)組,沒(méi)問(wèn)題把。咋們?cè)谡{(diào)用mas_makeConstraints:方法時(shí)可以用一個(gè)數(shù)組來(lái)接收,沒(méi)毛病。。看代碼

    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_offset(20);
        make.right.mas_offset(-20);
        make.top.mas_offset(100);
    }];

咋們?cè)趤?lái)看兩個(gè)方法,mas_offset()/mas_equalTo(),這兩個(gè)方法其實(shí)就是一個(gè)宏,點(diǎn)進(jìn)去看源碼如此

#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__)))


#ifdef MAS_SHORTHAND_GLOBALS

#define equalTo(...)                     mas_equalTo(__VA_ARGS__)
#define greaterThanOrEqualTo(...)        mas_greaterThanOrEqualTo(__VA_ARGS__)
#define lessThanOrEqualTo(...)           mas_lessThanOrEqualTo(__VA_ARGS__)

#define offset(...)                      mas_offset(__VA_ARGS__)

#endif

mas_equalTo 對(duì)應(yīng) equalTo 方法,mas_offset 對(duì)應(yīng) valueOffset 方法,這兩個(gè)其實(shí)就是 Block 執(zhí)行體,返回是調(diào)用者對(duì)象(連式編程的標(biāo)志性語(yǔ)法),這個(gè)對(duì)象也就是MASConstraint類對(duì)象。繼續(xù)下去。篇幅有點(diǎn)長(zhǎng),這個(gè)知識(shí)點(diǎn)就到這里把。

  1. 約束的卸載uninstall,使用MASConstraint對(duì)象調(diào)用這個(gè)uninstall,就會(huì)把約束從對(duì)應(yīng)的view上卸載掉;如下代碼
    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_offset(20);
        make.right.mas_offset(-20);
        make.top.mas_offset(100);
    }];
    //卸載約束
    for (MASConstraint *constraint in constraints) {
        [constraint uninstall];
    }

等價(jià)于

    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    __block MASConstraint *top = nil;
    __block MASConstraint *left = nil;
    __block MASConstraint *right = nil;
    [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        left = make.left.mas_offset(20);
        right = make.right.mas_offset(-20);
        top = make.top.mas_offset(100);
    }];
    //卸載約束
    [left uninstall];
    [right uninstall];
    [top uninstall];
  1. 約束的裝載install,使用MASConstraint對(duì)象調(diào)用這個(gè)install,就會(huì)把約束裝載到對(duì)應(yīng)的view上;如下代碼
    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    NSArray <MASConstraint *>*constraints = [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_offset(20);
        make.right.mas_offset(-20);
        make.top.mas_offset(100);
    }];
    //裝載約束
    //for (MASConstraint *constraint in constraints) {
    //   [constraint install];
    //}

等價(jià)于

    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    __block MASConstraint *top = nil;
    __block MASConstraint *left = nil;
    __block MASConstraint *right = nil;
    [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        left = make.left.mas_offset(20);
        right = make.right.mas_offset(-20);
        top = make.top.mas_offset(100);
    }];
    //裝載約束
    //[left install];
    //[right install];
    //[top install];

預(yù)備知識(shí)講完了,開(kāi)始完成功能

  1. 首先定義三個(gè)全局屬性必須得用到的
@interface Demo2ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end
  1. 寫(xiě)一個(gè)createDemo方法來(lái)實(shí)現(xiàn)案列, 并調(diào)用這個(gè)方法
- (void)viewDidLoad {
    [super viewDidLoad];
    [self createDemo];
}

- (void)createDemo {
    //...案例代碼在這里實(shí)現(xiàn)
}
  1. 創(chuàng)建 superView,不給 superView 高度,高度通過(guò)他的子視圖給撐起來(lái)
- (void)createDemo {
   UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:superView];
    [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(20);
        make.right.mas_equalTo(-20);
        make.top.mas_equalTo(100);
    }];
}
    
  1. 創(chuàng)建一個(gè)添加按鈕,沒(méi)點(diǎn)擊一下添加一個(gè)view在這個(gè)添加按鈕下面
- (void)createDemo {
    
    /*。。。。*/
    
    UIButton *button = [[UIButton alloc] init];
    [button setTitle:@"增加" forState:UIControlStateNormal];
    button.backgroundColor = UIColor.redColor;
    [button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
    [superView addSubview:button];
    [button mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(10);
        make.top.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        self.bottom = make.bottom.mas_equalTo(-10);//記錄下這個(gè)約束對(duì)象
        make.height.equalTo(@(100));
    }];
}
   
  1. superView的下方添加一個(gè)blueView,這個(gè)視圖blueView的頂部始終距離superView的底部10
- (void)createDemo {
    
    /*。。。。*/
    
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = UIColor.blueColor;
    [self.view addSubview:blueView];
    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(20);
        make.right.mas_equalTo(-20);
        make.top.mas_equalTo(superView.mas_bottom).mas_offset(10);
        make.height.mas_equalTo(@(100));
    }];
}
    
  1. superView 賦值給 self.superView,把button賦值給self.bottomView
- (void)createDemo {
    
    /*。。。。*/
    
    self.superView = superView;
    self.bottomView = button;
}

運(yùn)行效果圖如下

WechatIMG44.png
  1. 實(shí)現(xiàn)添加方法action:,就能實(shí)現(xiàn)動(dòng)態(tài)撐大父視圖了
static int num = 0;
- (void)action:(UIButton *)button {
    //卸載舊的底部約束
    [self.bottom uninstall];
    num += 1;
    YYLabel *view = [[YYLabel alloc] init];
    view.backgroundColor = UIColor.redColor;
    view.text = [NSString stringWithFormat:@"控件%d", num];
    view.textAlignment = NSTextAlignmentCenter;
    view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [self.superView addSubview:view];

    //給新 view 添加約束
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.superView.mas_left).offset(10);
        make.top.mas_equalTo(self.bottomView.mas_bottom).offset(10);
        make.right.mas_equalTo(self.superView.mas_right).offset(-10);
        //添加新的底部約束
        self.bottom = make.bottom.mas_equalTo(self.superView.mas_bottom).offset(-10);
        make.height.equalTo(@(100));
    }];
    self.bottomView = view;
}

效果圖如下

Jan-18-2019 17-10-11.gif

masonry 在 UIScrollView 中的運(yùn)用

masonry + UIScrollView 通過(guò)兩個(gè)示例,一個(gè)是水平方向,另一個(gè)垂直方向,這也是平常開(kāi)發(fā)中會(huì)遇到的。在使用masonry對(duì)UIScrollView設(shè)置約束后,contentSize屬性就不管用了,而需要通過(guò)masonry 的規(guī)則在scrollView中添加一個(gè) contentView,其它的子視圖全部添加到 contentView 上,讓contentView來(lái)?yè)纹餟IScrollview的 contentSize。

水平方向滑動(dòng)

  1. 第一步創(chuàng)建一個(gè)Scrollview
    // 水平方向滾動(dòng)視圖
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.backgroundColor = UIColor.greenColor;
    scrollView.pagingEnabled = YES;
    [self.view addSubview:scrollView];
    //設(shè)置 Scrollview 的約束
    [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.view).offset(100);
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
        make.bottom.mas_equalTo(-100);
    }];
  1. 創(chuàng)建一個(gè) contentView 放到Scrollview上,并設(shè)置約束
    // 設(shè)置scrollView的子視圖,即過(guò)渡視圖contentSize
    UIView *contentView = [[UIView alloc] init];
    [scrollView addSubview:contentView];
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(scrollView);
        make.height.mas_equalTo(scrollView);
    }];
  1. 動(dòng)態(tài)添加子視圖到 contentView 上
    UIView *previousView = nil;
    for (int i = 0; i < 10; i++) {
        YYLabel *label = [[YYLabel alloc] init];
        label.textAlignment = NSTextAlignmentCenter;
        label.numberOfLines = 2;
        label.backgroundColor = UIColor.redColor;
        label.text = [NSString stringWithFormat:@"水平方向\n第 %d 個(gè)視圖", (i + 1)];

        // 添加到父視圖,并設(shè)置過(guò)渡視圖中子視圖的約束
        [contentView addSubview:label];
        [label mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(contentView).offset(20);
            make.bottom.equalTo(contentView).offset(-20);
            make.width.equalTo(scrollView).offset(-40);
            if (previousView) {
                make.left.mas_equalTo(previousView.mas_right).offset(40);
            } else {
                make.left.mas_equalTo(20);
            }
        }];
        previousView = label;
    }
  1. 設(shè)置 contentView 的right約束,這個(gè)是很關(guān)鍵的位置
    //設(shè)置將影響到scrollView的contentSize
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.mas_equalTo(previousView.mas_right).offset(20);
    }];

運(yùn)行結(jié)果如下

Jan-18-2019 17-52-54.gif

垂直方向滑動(dòng)

垂直方向上跟水平方向上的實(shí)現(xiàn)方式大致相同,我就直接粘代碼過(guò)來(lái)了


@interface Demo3ViewController ()
@property (nonatomic, weak) UIView *superView;
@property (nonatomic, weak) UIView *bottomView;
@property (nonatomic, weak) MASConstraint *bottom;
@end

@implementation Demo3ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createDemo];
}

- (void)createDemo {
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.backgroundColor = UIColor.greenColor;
    [self.view addSubview:scrollView];
    [scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(0);
        make.right.mas_equalTo(-10.0);
        make.height.mas_equalTo(self.view).offset(-100);
    }];
    
    UIView *superView = [[UIView alloc] init];
    superView.backgroundColor = UIColor.greenColor;
    [scrollView addSubview:superView];
    [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(scrollView).with.insets(UIEdgeInsetsZero);
        make.width.mas_equalTo(scrollView);
    }];
    
    UIButton *button = [[UIButton alloc] init];
    [button setTitle:@"增加" forState:UIControlStateNormal];
    button.backgroundColor = UIColor.redColor;
    [button addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
    [superView addSubview:button];
    [button mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.mas_equalTo(0);
        make.height.mas_equalTo(100);
        make.top.mas_equalTo(20);
    }];
    
    self.superView = superView;
    self.bottomView = button;
    //設(shè)置 scrollview 的 contentSize
    [self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
        self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
    }];
}

static int num = 0;
- (void)action:(UIButton *)button {
    //取消底部約束
    [self.bottom uninstall];
    num += 1;
    YYLabel *view = [[YYLabel alloc] init];
    view.backgroundColor = UIColor.redColor;
    view.text = [NSString stringWithFormat:@"控件%d", num];
    view.textAlignment = NSTextAlignmentCenter;
    view.textVerticalAlignment = YYTextVerticalAlignmentCenter;
    [self.superView addSubview:view];

    //給新 view 添加約束
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(self.superView).offset(20);
        make.right.mas_equalTo(self.superView).offset(-20);
        make.height.mas_equalTo(100);
        make.top.mas_equalTo(self.bottomView.mas_bottom).offset(20);
    }];
    
    //記錄最下面的 view
    self.bottomView = view;
    
    //設(shè)置新的 contentSize
    [self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
        self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
    }];
}

結(jié)果如下

Jan-18-2019 18-04-42.gif

masonry 多列等寬

固定間距

masonry提供了實(shí)現(xiàn)多列等高API,指定 item 之間的間距,然后 item 的寬或者高動(dòng)態(tài)變化

/**
 *  distribute with fixed spacing
 *
 *  @param axisType     which axis to distribute items along
 *  @param fixedSpacing the spacing between each item
 *  @param leadSpacing  the spacing before the first item and the container
 *  @param tailSpacing  the spacing after the last item and the container
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

用法如下

- (void)createDemo {
    NSMutableArray *views = [NSMutableArray array];
    for (NSInteger i = 0; i < 3; i++) {
        YYLabel *item = [[YYLabel alloc] init];
        view.backgroundColor = UIColor.greenColor;
        view.textAlignment = NSTextAlignmentCenter;
        view.text = [NSString stringWithFormat:@"%ld",i];
        [views addObject:item];
        [self.view addSubview:item];
    }
    [views mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.mas_equalTo(self.view);
        make.height.mas_equalTo(100);
    }];
    [views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
                       withFixedSpacing:50
                            leadSpacing:10
                            tailSpacing:20];
}
WechatIMG46.jpeg

固定 item 寬度

masonry提供了實(shí)現(xiàn)多列等高API,指定 item 寬度或者高度,然后 item 之間的間距動(dòng)態(tài)變化,方法描述

/**
 *  distribute with fixed item size
 *
 *  @param axisType        which axis to distribute items along
 *  @param fixedItemLength the fixed length of each item
 *  @param leadSpacing     the spacing before the first item and the container
 *  @param tailSpacing     the spacing after the last item and the container
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;

用法

- (void)createDemo {
    NSMutableArray *views = [NSMutableArray array];
    for (NSInteger i = 0; i < 3; i++) {
        YYLabel *item = [[YYLabel alloc] init];
        item.backgroundColor = UIColor.greenColor;
        item.textAlignment = NSTextAlignmentCenter;
        item.text = [NSString stringWithFormat:@"%ld",i];
        [views addObject:item];
        [self.view addSubview:item];
    }
    [views mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.mas_equalTo(self.view);
        make.height.mas_equalTo(100);
    }];
    [views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
                    withFixedItemLength:100
                            leadSpacing:50
                            tailSpacing:50];
}
WechatIMG47.jpeg

masonry 設(shè)置寬高比例

在 masonry 提供了multipliedBy()函數(shù)用來(lái)處理布局比例問(wèn)題
,API

/**
 *  Sets the NSLayoutConstraint multiplier property
 */
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;

用法

- (void)createDemo {
    //示例1
    YYLabel *superView = [[YYLabel alloc] init];
    superView.text = @"示例2";
    superView.textAlignment = NSTextAlignmentCenter;
    superView.backgroundColor = UIColor.redColor;
    [self.view addSubview:superView];
    [superView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(0);
        //superView.width = superView.height = self.view.width * 0.5;
        make.width.height.mas_equalTo(self.view.mas_width).multipliedBy(0.5);
    }];
    
    //示例2
    YYLabel *subView = [[YYLabel alloc] init];
    subView.text = @"示例2";
    subView.textAlignment = NSTextAlignmentCenter;
    subView.backgroundColor = UIColor.blueColor;
    [superView addSubview:subView];
    [subView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(0);
        make.width.mas_equalTo(superView);
        //subView.height = subView.width * 0.5;
        make.height.mas_equalTo(subView.mas_width).multipliedBy(0.5);
    }];
}

運(yùn)行結(jié)果如下

WechatIMG48.jpeg

masonry UIButton 自適應(yīng)寬度

在 UIButton 自使用中需要使用到 mas_greaterThanOrEqualTo(value) 以及 mas_lessThanOrEqualTo(value)方法,mas_greaterThanOrEqualTo(value) 大于等于 value,mas_lessThanOrEqualTo(value)則是小于等于value

示例如下

    UIButton *btn = [[UIButton alloc] init];
    btn.backgroundColor = [UIColor blueColor];
    [btn setTitle:@"UIButton寬度" forState:UIControlStateNormal];
    [btn setImage:[UIImage imageNamed:@"icon"] forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    [btn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(self.view);
        make.height.mas_equalTo(@[btn.titleLabel.mas_height, btn.imageView.mas_height]);
        make.width.mas_lessThanOrEqualTo(kScreenWidth);
    }];

clicked:方法實(shí)現(xiàn)

- (void)clicked:(UIButton *)btn {
    [btn setTitle:[btn.currentTitle stringByAppendingString:@"自適應(yīng)"] forState:UIControlStateNormal];
}

看看效果怎么樣

Jan-18-2019 20-06-16.gif

UIButton 還有很多玩法,這里就不一一舉例了

masonry UILabel 自適應(yīng)寬度/高度

  • 對(duì)于 UILabel 自適應(yīng)寬度只需要使用 mas_lessThanOrEqualTo() 方法就能達(dá)到
  • 當(dāng)寬度達(dá)到極限后開(kāi)始換行需要設(shè)置兩個(gè)參數(shù),UILabel的 numberOfLines 屬性和 preferredMaxLayoutWidth 屬性,

代碼實(shí)現(xiàn)

//普通文本
- (void)createDemo {
    self.label2 = [[UILabel alloc]init];
    self.label2.tag = 100;
    [self.view addSubview:self.label2];
    self.label2.text = @"最近是用Masonry";
    self.label2.backgroundColor = UIColor.redColor;
    [self.label2 setPreferredMaxLayoutWidth:self.view.width - 30];
    self.label2.numberOfLines = 0;
    [self.label2 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
    [self.label2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(100);
        make.left.mas_equalTo(15);
    }];

    UIButton *btn = [[UIButton alloc] init];
    btn.backgroundColor = [UIColor blueColor];
    [btn setTitle:@"添加文字" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    [btn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.label2.mas_bottom).mas_offset(20);
        make.centerX.mas_equalTo(self.view);
        make.height.mas_equalTo(50);
        make.width.mas_lessThanOrEqualTo(kScreenWidth);
    }];
    
}
- (void)clicked {
    self.label2.text = [self.label2.text stringByAppendingString:@"Masonry自動(dòng)布局UILabel"];
}

結(jié)果如下

Jan-18-2019 20-57-21.gif

masonry YYLabel 自適應(yīng)寬度/高度

代碼實(shí)現(xiàn)

- (void)createDemo {
    self.label1 = [[YYLabel alloc] init];
    self.label1.text = @"最近是用Masonry自動(dòng)布局UILabel的時(shí)候,;這些東西之后,label還是沒(méi)有換行。最近是用Masonry自動(dòng)布局UILabel的時(shí)候,";
    self.label1.backgroundColor = UIColor.greenColor;
    self.label1.numberOfLines = 0;
    self.label1.preferredMaxLayoutWidth = self.view.width - 30;
    [self.view addSubview:self.label1];
    [self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(100);
        make.left.mas_equalTo(15);
    }];
    
    UIButton *btn = [[UIButton alloc] init];
    btn.backgroundColor = [UIColor blueColor];
    [btn setTitle:@"添加文字" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    [btn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.label1.mas_bottom).mas_offset(20);
        make.centerX.mas_equalTo(self.view);
        make.height.mas_equalTo(50);
        make.width.mas_lessThanOrEqualTo(kScreenWidth);
    }];
    
}
- (void)clicked {
    self.label1.text = [self.label1.text stringByAppendingString:@"Masonry自動(dòng)布局YYLabel"];
}

結(jié)果如下


Jan-18-2019 20-43-44.gif

masonry 實(shí)現(xiàn)動(dòng)態(tài) UITabelViewCell

先看效果

Jan-18-2019 21-03-23.gif

demo實(shí)現(xiàn)得很粗糙,但是基本功能都實(shí)現(xiàn)了。實(shí)現(xiàn)動(dòng)態(tài) UITabelViewCell 需要了解到的知識(shí)點(diǎn)

  1. 不設(shè)置cell的高度
  2. 不實(shí)現(xiàn)返回cell高度的代理方法
  3. 設(shè)置 UITabelViewCell的estimatedRowHeight屬性
  4. 將tableview的rowHeight屬性設(shè)置為UITableViewAutomaticDimension

示例如下

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.estimatedRowHeight = 100;
        _tableView.rowHeight = UITableViewAutomaticDimension;
        [_tableView registerClass:Demo8Cell.class forCellReuseIdentifier:@"cellID"];
        [self.view addSubview:_tableView];
    }
    return _tableView;
}

關(guān)于 tableview 需要設(shè)置的就這些,剩下的在 tableviewCell 的動(dòng)態(tài)高度在cell內(nèi)部設(shè)置

關(guān)于 Demo8Cell 內(nèi)部實(shí)現(xiàn)如下

.h

@class Demo8Model;
NS_ASSUME_NONNULL_BEGIN

@interface Demo8Cell : UITableViewCell
@property (nonatomic, strong) UILabel *messageLabel;

- (void)setmessage:(Demo8Model *)message;
@end

.m

@interface Demo8Cell ()
@property (nonatomic, strong) UIView *picContentView;
@property (nonatomic, strong) UIView *timerView;
@property (nonatomic, strong) UIView *likeView;
@end

@implementation Demo8Cell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier  {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        [self createUI];
    }
    return self;
}

- (void)createUI {
    self.messageLabel = [[UILabel alloc] init];
    self.messageLabel.numberOfLines = 0;
    [self.contentView addSubview:self.messageLabel];
    [self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(8);
        make.left.mas_equalTo(10);
        make.right.mas_equalTo(-10);
    }];
    self.picContentView = [[UIView alloc]init];
    self.picContentView.backgroundColor = UIColor.grayColor;
    [self.contentView addSubview:self.picContentView];
    [self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.messageLabel.mas_bottom).offset(15);
        make.left.mas_offset(50);
        make.right.mas_offset(-20);
    }];
    
    self.timerView = [[UIView alloc]init];
    self.timerView.backgroundColor = UIColor.redColor;
    [self.contentView addSubview:self.timerView];
    [self.timerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
        make.left.mas_equalTo(50);
        make.height.mas_equalTo(30);
        make.width.mas_equalTo(50);
        //關(guān)鍵位置
        make.bottom.mas_equalTo(-8);
    }];
    
    self.likeView = [[UIView alloc] init];
    self.likeView.backgroundColor = UIColor.redColor;
    [self.contentView addSubview:self.likeView];
    [self.likeView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.picContentView.mas_bottom).mas_offset(10);
        make.right.mas_equalTo(-20);
        make.height.mas_equalTo(30);
        make.width.mas_equalTo(50);
    }];
}
- (void)setmessage:(Demo8Model *)message {
    // 創(chuàng)建一個(gè)可變屬性字符串
    NSMutableAttributedString *finalStr = [[NSMutableAttributedString alloc] init];
    
    // 創(chuàng)建姓名
    NSAttributedString *nameStr = [[NSAttributedString alloc] initWithString:message.name attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]}];
    
    // 創(chuàng)建發(fā)言內(nèi)容
    NSAttributedString *messageStr = [[NSAttributedString alloc] initWithString:message.message attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor blackColor]}];
    
    // 拼接上兩個(gè)字符串
    [finalStr appendAttributedString:nameStr];
    [finalStr appendAttributedString:messageStr];
    self.messageLabel.attributedText = finalStr;
    //移除所有圖片
    [self.picContentView removeAllSubviews];
    [self createDemo:message.picNum];
}

- (void)createDemo:(NSInteger)itemNum {
    //假設(shè)要顯示 num 個(gè)item
    NSInteger num = itemNum;
    //每行顯示的個(gè)數(shù)
    NSInteger count = 3;
    //顯示的總行數(shù)
    NSInteger rowNum = (num/count) + ((NSInteger)(num%count>0));
    UIView *lastView = nil;
    for (int i = 0; i < rowNum; i ++) {
        NSMutableArray *masonryViewArray = [NSMutableArray array];
        for (int j = 0; j < count; j ++) {
            UIView *view = [[UIView alloc] init];
            if ((i * count) + j > num-1) {
                view.backgroundColor = [UIColor clearColor];
            } else {
                view.backgroundColor = [UIColor redColor];
            }
            [self.picContentView addSubview:view];
            [masonryViewArray addObject:view];
            lastView = view;
        }
        // 固定 item 之間的間距,item 的寬或者高自動(dòng)縮放
        [masonryViewArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:30 leadSpacing:10 tailSpacing:10];
        // 設(shè)置array的垂直方向的約束
        [masonryViewArray mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(@((100 * i) + 10));
            make.height.equalTo(@80);
        }];
    }
    if (lastView) {
        [self.picContentView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.bottom.mas_equalTo(lastView.mas_bottom).mas_offset(20);
        }];
    }
}
@end

未完待續(xù)。。。。

最后編輯于
?著作權(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),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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