2018-06-13 Masonry的学习

作者: 肠粉白粥_Hoben | 来源:发表于2018-06-13 15:56 被阅读52次

    配置这玩意花了我一个早上_(:з」∠)_,详情请看之前我写的文章。

    今天,参考了Masonry介绍与使用实践(快速上手Autolayout),我们来学习一下怎么使用这个Masonry。

    先看看流程是怎样的:
    初始化subView -> 添加subView ->为subView添加约束(位置、大小等)

    1.简单居中

    首先来个最简单的:

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        //初始化subView
        UIView *sv = [[UIView alloc] init];
        sv.backgroundColor = [UIColor blackColor];
        
        //添加subView
        [self.view addSubview: sv];
        
        //为subView添加约束
        [sv mas_makeConstraints: ^(MASConstraintMaker *make) {
            //居中约束
            make.center.equalTo(self.view);
            
            //尺寸约束
            make.size.mas_equalTo(CGSizeMake(300, 300));
        }];
    }
    

    其中mas_equalTo支持的类型,除了NSNumber支持的那些数值类型之外 就只支持CGPoint、CGSize、UIEdgeInsets

    而equalTo支持的类型为id

    参考mas_equalTo和equalTo区别与使用

    以下两者等价:

    1. mas_EqualTo(100)

    2. equalTo(@100)

    以下两者等价:

    1. make.bottom.mas_equalTo(view.mas_bottom);

    2. make.bottom.equalTo(view);

    // 添加这个宏,就不用带mas_前缀
    #define MAS_SHORTHAND
    // 添加这个宏,equalTo就等价于mas_equalTo
    #define MAS_SHORTHAND_GLOBALS
    // 这个头文件一定要放在上面两个宏的后面
    #import "Masonry.h"
    

    2.让一个view略小于SuperView

    在view已经建立好的基础上再建立一个subView2,这次是基于边缘来定位:

    UIView *sv1 = [[UIView alloc] init];
    sv1.backgroundColor = [UIColor redColor];
    
    [sv addSubview: sv1];
    
    [sv1 mas_makeConstraints: ^(MASConstraintMaker *make) {
        //方法1
        make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
        
        //方法2
        make.top.equalTo(sv).with.offset(10);
        make.left.equalTo(sv).with.offset(10);
        make.bottom.equalTo(sv).with.offset(-10);
        make.right.equalTo(sv).with.offset(-10);
        
        //方法3
        make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
    }];
    

    在这里,.and和.with其实什么都没做,可加可不加,但是加起来就看上去很舒服。


    3.加入两个view并设置大小

    这次来基于位置来定位两个view,并引入我们的精髓——autoLayout

    int padding1 = 10;
    
    UIView *sv2 = [[UIView alloc] init];
    UIView *sv3 = [[UIView alloc] init];
    sv2.backgroundColor = [UIColor orangeColor];
    sv3.backgroundColor = [UIColor orangeColor];
    
    [self.view addSubview: sv2];
    [self.view addSubview: sv3];
    
    [sv2 mas_makeConstraints: ^(MASConstraintMaker *make) {
        //令纵向中点相等
        make.centerY.equalTo(sv.mas_centerY);
        
        //距离左边10
        make.left.equalTo(sv.mas_left).with.offset(padding1);
        
        //两者间距10
        make.right.equalTo(sv3.mas_left).with.offset(-padding1);
        
        //设置sv2高度
        make.height.equalTo(@150);
        
        //和sv3等宽
        make.width.equalTo(sv3);
    }];
    [sv3 mas_makeConstraints: ^(MASConstraintMaker *make) {
        //令纵向中点相等
        //以下两者等价
    //      make.centerY.mas_equalTo(sv.mas_centerY);
        make.centerY.equalTo(sv.mas_centerY);
        
        //左边距离sv2的右边10
        make.left.equalTo(sv2.mas_right).with.offset(padding1);
        
        //右边距离sv的右边10
        //以下两者等价
    //        make.right.mas_equalTo(sv.mas_right).with.offset(-padding1);
        make.right.equalTo(sv.mas_right).with.offset(-padding1);
        
        //设置sv3高度
        //以下两者等价
    //        make.height.mas_equalTo(150);
        make.height.equalTo(@150);
        
        //和sv2等宽
        //以下两者等价
    //        make.width.equalTo(sv2);
        make.width.equalTo(sv2.mas_width);
    }];
    

    看到我们的结果后,很好奇,width明明就没有设置大小,但是还是给我们显示出来了,这就是autoLayout的精髓了,因为我们能通过已知的约束求出sv2和sv3的width:

    • sv的width为300
    • sv2的left和sv的left距离10
    • sv3的right和sv的right距离10
    • sv2的right和sv3的left距离10
    • sv2和sv3的width相等

    因此,width = (300 - 10 - 10 - 10) / 2 = 135
    由于已经设置了centerY

    4.用UIScrollView包含container展示

    这次我们再用UIScrollView来体现autoLayout的优越性:

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.backgroundColor = [UIColor whiteColor];
    [sv addSubview: scrollView];
    [scrollView mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.edges.equalTo(sv).insets(UIEdgeInsetsMake(5, 5, 5, 5));
    }];
    
    
    UIView *container = [[UIView alloc] init];
    [scrollView addSubview: container];
    
    UIView *lastView = nil;
    
    [container mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.edges.equalTo(scrollView);
        //注意这里要设置多width
        make.width.equalTo(scrollView);
    }];
    
    int count = 10;
    
    for (int i = 1; i <= count; i++) {
        UIView *thisView = [[UIView alloc] init];
        [container addSubview: thisView];
        thisView.backgroundColor = [UIColor colorWithHue:( arc4random() % 256 / 256.0 )
                                              saturation:( arc4random() % 128 / 256.0 ) + 0.5
                                              brightness:( arc4random() % 128 / 256.0 ) + 0.5
                                                   alpha:1];
        [thisView mas_makeConstraints: ^(MASConstraintMaker *make) {
            make.width.equalTo(container);
            make.left.and.right.equalTo(container);
            make.height.equalTo(@(20 * i));
            if (lastView) {
                //lastView为上一个view,则接着上一个view
                make.top.equalTo(lastView.mas_bottom);
            }
            else {
                make.top.equalTo(container.mas_top);
            }
        }];
        lastView = thisView;
    }
    
    [container mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.bottom.equalTo(lastView.mas_bottom);
    }];
    

    通过自己手敲代码重现一次,有一件事情很重要:就是必须声明该布局的大小(width、height)和位置(left、right、bottom、top或者edges)!

    可以看到,这样就可以自动确定子控件的高度了。



    5.等间距填充

    autoLayout并没有直接提供等间隙排列的方法,因此,此文的作者写了一个Category,思路大概是,获得count+1个等宽高空格,用于填充它们之间的间隙,然后链式调用,利用autoLayout,来进行等间距填充。

    - (void) distributeSpacingHorizontallyWith: (NSArray *) views
    {
        NSMutableArray *spaces = [NSMutableArray arrayWithCapacity: views.count + 1];
        
        //生成(views.count+1)个宽高相等的空格,用于填充views之间的空隙
        for (int i = 0; i < views.count + 1; i++) {
            UIView *v = [[UIView alloc] init];
            [spaces addObject: v];
            [self addSubview: v];
            
            [v mas_makeConstraints: ^(MASConstraintMaker *make) {
                //width = height
                make.width.equalTo(v.mas_height);
            }];
        }
        
        UIView *v0 = spaces[0];
        
        [v0 mas_makeConstraints: ^(MASConstraintMaker *make) {
            make.left.equalTo(self.mas_left);
            make.centerY.equalTo(((UIView *) views[0]).mas_centerY);
        }];
        
        UIView *lastSpace = v0;
        
        for (int i = 0; i < views.count; i++) {
            //从左到右读取view以及space
            UIView *obj = views[i];
            UIView *space = spaces[i + 1];
            [obj mas_makeConstraints: ^(MASConstraintMaker *make) {
                make.left.equalTo(lastSpace.mas_right);
            }];
            
            [space mas_makeConstraints: ^(MASConstraintMaker *make) {
                make.left.equalTo(obj.mas_right);
                //记得保持水平相等
                make.centerY.equalTo(obj.mas_centerY);
                make.width.equalTo(v0);
            }];
            
            lastSpace = space;
        }
        
        [lastSpace mas_makeConstraints: ^(MASConstraintMaker *make) {
            make.right.equalTo(self.mas_right);
        }];
    }
    
    - (void) distributeSpacingVerticallyWith: (NSArray *) views
    {
        NSMutableArray *spaces = [NSMutableArray arrayWithCapacity: views.count + 1];
        
        for (int i = 0; i < views.count + 1; i++) {
            UIView *v =[[UIView alloc] init];
            [spaces addObject: v];
            [self addSubview: v];
            [v mas_makeConstraints: ^(MASConstraintMaker *make) {
                make.width.equalTo(v.mas_height);
            }];
        }
        
        UIView *v0 = spaces[0];
        
        [v0 mas_makeConstraints: ^(MASConstraintMaker *make) {
            make.top.equalTo(self.mas_top);
            make.centerX.equalTo(((UIView *)views[0]).mas_centerX);
        }];
        
        UIView *lastSpace = v0;
        
        for (int i = 0; i < views.count; i++) {
            //从上到下读取view以及space
            UIView *obj = views[i];
            UIView *space = spaces[i + 1];
            
            [obj mas_makeConstraints: ^(MASConstraintMaker *make) {
                make.top.equalTo(lastSpace.mas_bottom);
            }];
            
            [space mas_makeConstraints: ^(MASConstraintMaker *make) {
                make.top.equalTo(obj.mas_bottom);
                make.centerX.equalTo(self.mas_centerX);
                make.height.equalTo(v0);
            }];
            
            lastSpace = space;
        }
        
        [lastSpace mas_makeConstraints: ^(MASConstraintMaker *make) {
            make.bottom.equalTo(self.mas_bottom);
        }];
    }
    
    UIView *fatherView = [[UIView alloc] init];
    UIView *verView1 = [[UIView alloc] init];
    UIView *verView2 = [[UIView alloc] init];
    UIView *horView1 = [[UIView alloc] init];
    UIView *horView2 = [[UIView alloc] init];
    
    [sv addSubview: fatherView];
    [sv addSubview: verView1];
    [sv addSubview: verView2];
    [sv addSubview: horView1];
    [sv addSubview: horView2];
    
    fatherView.backgroundColor = [UIColor redColor];
    verView1.backgroundColor = [UIColor redColor];
    verView2.backgroundColor = [UIColor redColor];
    horView1.backgroundColor = [UIColor redColor];
    horView2.backgroundColor = [UIColor redColor];
    
    [fatherView mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.centerX.equalTo(@[verView1, verView2]);
        make.centerY.equalTo(@[horView1, horView2]);
        make.size.mas_equalTo(CGSizeMake(40, 40));
    }];
    
    [verView1 mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(50, 20));
    }];
    
    [verView2 mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(40, 60));
    }];
    
    [horView1 mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(70, 20));
    }];
    
    [horView2 mas_makeConstraints: ^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(50, 50));
    }];
    
    [sv distributeSpacingVerticallyWith: @[fatherView, verView1, verView2]];
    [sv distributeSpacingHorizontallyWith: @[fatherView, horView1, horView2]];
    

    6.学会debug

    在这么复杂的非可视化页面构造中,难免会出现一些constraint的冲突,就会出现以下报错:



    这些错误可以通过编译,却会把界面弄得面目全非,但是,这么多的代码怎么找。。

    幸好,红框框住的错误信息已经给我们提示了,我们需要加个断点,来定位到哪里出现了错误:



    可以看到,红框的内容就是罪魁祸首,这里我不小心把space写成spaces了,多了一个字母,就出bug了,挺烦的= =



    经过debug之后,可以看到效果如下:

    相关文章

      网友评论

        本文标题:2018-06-13 Masonry的学习

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