masonry 使用笔记

作者: 朽木自雕也 | 来源:发表于2019-01-18 21:49 被阅读60次

    为什么要做这个笔记

    masonry 可以说是当前 iOS开发中最流行的 Autolayout框架,其极大的简化了苹果原生提供的AutoLayout语法。目前很多大厂也是用的这个自动布局框架,我司也在用。在此之前我一只在用另一个叫 SDAutolayout的自动布局库,所以 masonry 是个初学者,如果写得不好的地方还希望大佬指点江山。经过前段时间的开发项目,对masonry框架有了大致的认识,用法上面基本能解决所有布局问题。

    masonry 基础约束用法

    • 首先先提及一下,view 在执行 masonry 布局之前必须添加到父视图上
    • 约束的写法有好几种,我先拿三种来举例
    1. 第一种。mas_equalTo()方法传入一个依赖的约束边,如下面示例中“self.view.mas_left”,后面跟着 mas_offset()方法可以传入一个值,这个值是相对于所依赖约束的偏移量。mas_offset()也可以不写,默认偏移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);//左边相对于 self.view 的 left 偏移50个单位
            make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);//右边相对于 self.view 的 right 偏移-50个单位
            make.top.mas_equalTo(self.view.mas_top).mas_offset(100);//顶边相对于 self.view 的 top 偏移100个单位
            make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);//底边相对于 self.view 的 bottom 偏移-100个单位
        }];
    
    1. 第二种。mas_equalTo()只需要传入相对的约束的视图,不需要指定约束边,默认取前面第一个需要添加约束的边
        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);//等价于 make.left.mas_equalTo(self.view.mas_left).mas_offset(50);
            make.right.mas_equalTo(self.view).mas_offset(-50);//等价于 make.right.mas_equalTo(self.view.mas_right).mas_offset(-50);
            make.top.mas_equalTo(self.view).mas_offset(100);//等价于 make.top.mas_equalTo(self.view.mas_top).mas_offset(100);
            make.bottom.mas_equalTo(self.view).mas_offset(-100);//等价于 make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-100);
        }];
    
    1. 第三种。mas_equalTo() 传入一个值,这个值就是相对于依赖父视图对应相同约束的偏移量
        UIView *demoView = [[UIView alloc] init];
        demoView.backgroundColor = UIColor.greenColor;
        [self.view addSubview:demoView];
        [demoView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(50);//等价于 make.left.mas_equalTo(demoView.superview.mas_left).mas_offset(50);
            make.right.mas_equalTo(-50);//等价于 make.right.mas_equalTo(demoView.superview.mas_right).mas_offset(-50);
            make.top.mas_equalTo(100);//等价于 make.top.mas_equalTo(demoView.superview.mas_top).mas_offset(100);
            make.bottom.mas_equalTo(-100);//等价于 make.bottom.mas_equalTo(demoView.superview.mas_bottom).mas_offset(-100);
        }];
    

    三种写法结果是一致的,效果图如下

    WechatIMG38.png

    看你个人喜欢用哪一种,我个人比较懒,喜欢用第三种,所以都是以第三种写法作为描述

    居左上

        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

    子控件来撑起父控件的高度

    平常在开发过程中,经常有这种情况就是父控件高度是根据子控件内容动态变化,用masonry来实现这个功能相当简单,这里有几个知识点;

    1. 约束类对象MASConstraint,通过点进mas_makeConstraints:方法的实现,源码如下
    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        block(constraintMaker);
        return [constraintMaker install];
    }
    

    咋们暂且先不管 MASConstraintMaker 类,找到最后一句constraintMaker对象调用了 install 方法并返回;进入到这个install的实现,源码实现如下

    - (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;
    }
    

    其中最上面的那个判断条件在调用mas_remakeConstraints:方法时会被执行到,咋们也不看。咋们看下面这一段,其实 self.constraints 数组 就是在mas_makeConstraints:的 block 块中添加的所有约束对象,接下来 self.constraints 执行 copy 并遍历执行 constraint.updateExisting = self.updateExisting;[constraint install];,for 循环体中的第一句是标记更新约束还是新添加的约束,第二句是对约束装载,如果把第二句给注视掉,则添加的所有约束都不会被添加上,各位可以试一试;在方法的最后 返回了constraints数组,这个数组里面装的是 MASConstraint 类对象,再回到上面 mas_makeConstraints:方法中,最后的 return [constraintMaker install];实际上就是返回另一个约束对象的数组,没问题把。咋们在调用mas_makeConstraints:方法时可以用一个数组来接收,没毛病。。看代码

        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);
        }];
    

    咋们在来看两个方法,mas_offset()/mas_equalTo(),这两个方法其实就是一个宏,点进去看源码如此

    #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 对应 equalTo 方法,mas_offset 对应 valueOffset 方法,这两个其实就是 Block 执行体,返回是调用者对象(连式编程的标志性语法),这个对象也就是MASConstraint类对象。继续下去。篇幅有点长,这个知识点就到这里把。

    1. 约束的卸载uninstall,使用MASConstraint对象调用这个uninstall,就会把约束从对应的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];
        }
    
    

    等价于

        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对象调用这个install,就会把约束装载到对应的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];
        //}
    
    

    等价于

        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];
    

    预备知识讲完了,开始完成功能

    1. 首先定义三个全局属性必须得用到的
    @interface Demo2ViewController ()
    @property (nonatomic, weak) UIView *superView;
    @property (nonatomic, weak) UIView *bottomView;
    @property (nonatomic, weak) MASConstraint *bottom;
    @end
    
    1. 写一个createDemo方法来实现案列, 并调用这个方法
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self createDemo];
    }
    
    - (void)createDemo {
        //...案例代码在这里实现
    }
    
    1. 创建 superView,不给 superView 高度,高度通过他的子视图给撑起来
    - (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. 创建一个添加按钮,没点击一下添加一个view在这个添加按钮下面
    - (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);//记录下这个约束对象
            make.height.equalTo(@(100));
        }];
    }
       
    
    1. superView的下方添加一个blueView,这个视图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;
    }
    
    

    运行效果图如下

    WechatIMG44.png
    1. 实现添加方法action:,就能实现动态撑大父视图了
    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 中的运用

    masonry + UIScrollView 通过两个示例,一个是水平方向,另一个垂直方向,这也是平常开发中会遇到的。在使用masonry对UIScrollView设置约束后,contentSize属性就不管用了,而需要通过masonry 的规则在scrollView中添加一个 contentView,其它的子视图全部添加到 contentView 上,让contentView来撑起UIScrollview的 contentSize。

    水平方向滑动

    1. 第一步创建一个Scrollview
        // 水平方向滚动视图
        UIScrollView *scrollView = [[UIScrollView alloc] init];
        scrollView.backgroundColor = UIColor.greenColor;
        scrollView.pagingEnabled = YES;
        [self.view addSubview:scrollView];
        //设置 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. 创建一个 contentView 放到Scrollview上,并设置约束
        // 设置scrollView的子视图,即过渡视图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. 动态添加子视图到 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 个视图", (i + 1)];
    
            // 添加到父视图,并设置过渡视图中子视图的约束
            [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. 设置 contentView 的right约束,这个是很关键的位置
        //设置将影响到scrollView的contentSize
        [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.right.mas_equalTo(previousView.mas_right).offset(20);
        }];
    

    运行结果如下

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

    垂直方向滑动

    垂直方向上跟水平方向上的实现方式大致相同,我就直接粘代码过来了

    
    @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;
        //设置 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;
        
        //设置新的 contentSize
        [self.superView mas_makeConstraints:^(MASConstraintMaker *make) {
            self.bottom = make.bottom.mas_equalTo(self.bottomView.mas_bottom);
        }];
    }
    
    

    结果如下

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

    masonry 多列等宽

    固定间距

    masonry提供了实现多列等高API,指定 item 之间的间距,然后 item 的宽或者高动态变化

    /**
     *  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提供了实现多列等高API,指定 item 宽度或者高度,然后 item 之间的间距动态变化,方法描述

    /**
     *  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 设置宽高比例

    在 masonry 提供了multipliedBy()函数用来处理布局比例问题
    ,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);
        }];
    }
    

    运行结果如下

    WechatIMG48.jpeg

    masonry UIButton 自适应宽度

    在 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:方法实现

    - (void)clicked:(UIButton *)btn {
        [btn setTitle:[btn.currentTitle stringByAppendingString:@"自适应"] forState:UIControlStateNormal];
    }
    

    看看效果怎么样

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

    UIButton 还有很多玩法,这里就不一一举例了

    masonry UILabel 自适应宽度/高度

    • 对于 UILabel 自适应宽度只需要使用 mas_lessThanOrEqualTo() 方法就能达到
    • 当宽度达到极限后开始换行需要设置两个参数,UILabel的 numberOfLines 属性和 preferredMaxLayoutWidth 属性,

    代码实现

    //普通文本
    - (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自动布局UILabel"];
    }
    

    结果如下

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

    masonry YYLabel 自适应宽度/高度

    代码实现

    - (void)createDemo {
        self.label1 = [[YYLabel alloc] init];
        self.label1.text = @"最近是用Masonry自动布局UILabel的时候,;这些东西之后,label还是没有换行。最近是用Masonry自动布局UILabel的时候,";
        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自动布局YYLabel"];
    }
    

    结果如下


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

    masonry 实现动态 UITabelViewCell

    先看效果

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

    demo实现得很粗糙,但是基本功能都实现了。实现动态 UITabelViewCell 需要了解到的知识点

    1. 不设置cell的高度
    2. 不实现返回cell高度的代理方法
    3. 设置 UITabelViewCell的estimatedRowHeight属性
    4. 将tableview的rowHeight属性设置为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;
    }
    

    关于 tableview 需要设置的就这些,剩下的在 tableviewCell 的动态高度在cell内部设置

    关于 Demo8Cell 内部实现如下

    .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);
            //关键位置
            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 {
        // 创建一个可变属性字符串
        NSMutableAttributedString *finalStr = [[NSMutableAttributedString alloc] init];
        
        // 创建姓名
        NSAttributedString *nameStr = [[NSAttributedString alloc] initWithString:message.name attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor redColor]}];
        
        // 创建发言内容
        NSAttributedString *messageStr = [[NSAttributedString alloc] initWithString:message.message attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:16], NSForegroundColorAttributeName: [UIColor blackColor]}];
        
        // 拼接上两个字符串
        [finalStr appendAttributedString:nameStr];
        [finalStr appendAttributedString:messageStr];
        self.messageLabel.attributedText = finalStr;
        //移除所有图片
        [self.picContentView removeAllSubviews];
        [self createDemo:message.picNum];
    }
    
    - (void)createDemo:(NSInteger)itemNum {
        //假设要显示 num 个item
        NSInteger num = itemNum;
        //每行显示的个数
        NSInteger count = 3;
        //显示的总行数
        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 的宽或者高自动缩放
            [masonryViewArray mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:30 leadSpacing:10 tailSpacing:10];
            // 设置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
    

    未完待续。。。。

    相关文章

      网友评论

        本文标题:masonry 使用笔记

        本文链接:https://www.haomeiwen.com/subject/daagdqtx.html