masonry 学习笔记 一(基础尝试)

一、为什么要学masonry(why)?

目前iOS开发中大多数页面都已经开始使用Interface Builder的方式进行UI开发了,但是在一些变化比较复杂的页面,还是需要通过代码来进行UI开发的。
而且有很多比较老的项目,本身就还在采用纯代码的方式进行开发。
而现在iPhone和iPad屏幕尺寸越来越多,虽然开发者只需要根据屏幕点进行开发,而不需要基于像素点进行UI开发。但如果在项目中根据不同屏幕尺寸进行各种判断,
写死坐标的话,这样开发起来是很吃力的。
所以一般用纯代码开发UI的话,一般都是配合一些自动化布局的框架进行屏幕适配。苹果为我们提供的适配框架有:VFL、UIViewAutoresizing、Auto Layout、
Size Classes等。
其中Auto Layout是使用频率最高的布局框架,但是其也有弊端。就是在使用UILayoutConstraint的时候,会发现代码量很多,而且大多都是重复性的代码,
以至于好多人都不想用这个框架。
后来Github上的出现了基于UILayoutConstraint封装的第三方布局框架Masonry,Masonry使用起来非常方便,本篇文章就详细讲一下Masonry的使用。

二、masonry是什么(what)?

Masonry是一个对系统NSLayoutConstraint进行封装的第三方自动布局框架,采用链式编程的方式提供给开发者API。系统AutoLayout支持的操作,Masonry都支持,
相比系统API功能来说,Masonry是有过之而无不及。
Masonry采取了链式编程的方式,代码理解起来非常清晰易懂,而且写完之后代码量看起来非常少。之前用NSLayoutConstraint写很多代码才能实现的布局,
用Masonry最少一行代码就可以搞定。下面看到Masonry的代码就会发现,太简单易懂了。
Masonry是同时支持Mac和iOS两个平台的,在这两个平台上都可以使用Masonry进行自动布局。我们可以从MASUtilities.h文件中,看到下面的定义,
这就是Masonry通过宏定义的方式,区分两个平台独有的一些关键字。
支持的属性:
@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;

 

  

三、怎样学习masonry(how)?

1.masonry遇到的坑

在使用Masonry进行约束时,不用设置weak控制器self,因为masonry的内容使用的不是block,不存在循环引用。
在使用Masonry进行约束时,有一些是需要注意的。
在使用Masonry添加约束之前,需要在addSubview之后才能使用,否则会导致崩溃。
在添加约束时初学者经常会出现一些错误,约束出现问题的原因一般就是两种:约束冲突和缺少约束。对于这两种问题,可以通过调试和log排查。
之前使用Interface Builder添加约束,如果约束有错误直接就可以看出来,并且会以红色或者黄色警告体现出来。而Masonry则不会直观的体现出来,而是以运行过程中崩溃或者打印异常log体现,所以这也是手写代码进行AutoLayout的一个缺点。
这个问题只能通过多敲代码,积攒纯代码进行AutoLayout的经验,慢慢就用起来越来越得心应手了。

  

2.基础API

mas_makeConstraints()    添加约束
mas_remakeConstraints()  移除之前的约束,重新添加新的约束
mas_updateConstraints()  更新约束

equalTo()       参数是对象类型,一般是视图对象或者mas_width这样的坐标系对象
mas_equalTo()   和上面功能相同,参数可以传递基础数据类型对象,可以理解为比上面的API更强大

width()         用来表示宽度,例如代表view的宽度
mas_width()     用来获取宽度的值。和上面的区别在于,一个代表某个坐标系对象,一个用来获取坐标系对象的值

3.修饰语句

Auto Boxing
上面例如equalTo或者width这样的,有时候需要涉及到使用mas_前缀,这在开发中需要注意作区分。
如果在当前类引入#import "Masonry.h"之前,用下面两种宏定义声明一下,就不需要区分mas_前缀。
// 定义这个常量,就可以不用在开发过程中使用"mas_"前缀。
#define MAS_SHORTHAND
// 定义这个常量,就可以让Masonry帮我们自动把基础数据类型的数据,自动装箱为对象类型。
#define MAS_SHORTHAND_GLOBALS
修饰语句
Masonry为了让代码使用和阅读更容易理解,所以直接通过点语法就可以调用,还添加了and和with两个方法。这两个方法内部实际上什么都没干,只是在内部将self直接返回,功能就是为了更加方便阅读,对代码执行没有实际作用。
例如下面的例子:

make.top.and.bottom.equalTo(self.containerView).with.offset(padding);

3.常用的方法

设置内边距

/**
 设置yellow视图和self.view等大,并且有10的内边距。
 注意根据UIView的坐标系,下面right和bottom进行了取反。所以不能写成下面这样,否则right、bottom这两个方向会出现问题。
 make.edges.equalTo(self.view).with.offset(10);

 除了下面例子中的offset()方法,还有针对不同坐标系的centerOffset()、sizeOffset()、valueOffset()之类的方法。
 */
[self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(self.view).with.offset(10);
    make.top.equalTo(self.view).with.offset(10);
    make.right.equalTo(self.view).with.offset(-10);
    make.bottom.equalTo(self.view).with.offset(-10);
}];
通过insets简化设置内边距的方式

// 下面的方法和上面例子等价,区别在于使用insets()方法。
[self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
    // 下、右不需要写负号,insets方法中已经为我们做了取反的操作了。
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];

4.常用例子

4.1 上下排列

    [self.view addSubview:self.blueView];
    [self.view addSubview:self.yellowView];
    [self.view addSubview:self.redView];

    //三个等高视图占一个屏幕,关键点inses内边距和高度可以同时等同于多个视图make.height.equalTo(@[self.redView,self.blueView]);
    //上下排列核心思想:起点redView视图固定上左右底,中间blueView固定左右底,底部yellowView固定 左右底,高度等高
1.基本用法

    CGFloat padding = 10;
    [self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.equalTo(self.view).insets(UIEdgeInsetsMake(padding, padding, 0, padding));
        make.bottom.equalTo(self.blueView.mas_top).offset(-10);
    }];
    [self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(0, padding, 0, padding));
        make.bottom.equalTo(self.yellowView.mas_top).offset(-10);
    }];
    [self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.bottom.equalTo(self.view).insets(UIEdgeInsetsMake(0, padding, padding, padding));
        make.height.equalTo(@[self.redView,self.blueView]);
    }];

#pragma mark - ??private
- (NSString *)ranomText{

    CGFloat length = arc4random()%50 +5;
    NSMutableString *str = [[NSMutableString alloc] init];
    for (NSInteger i = 0; i <length; i++) {
        [str appendString:@"测试一下啦!"];
    }
    return str;
}
- (UIView *)blueView{
    if (!_blueView) {
        _blueView = [[UIView alloc] init];
        [_blueView setBackgroundColor:[UIColor blueColor]];

    }
    return _blueView;
}
- (UIView *)yellowView{
    if (!_yellowView) {
        _yellowView = [[UIView alloc] init];
        [_yellowView setBackgroundColor:[UIColor yellowColor]];

    }
    return _yellowView;
}
- (UIView *)redView{
    if (!_redView) {
        _redView = [[UIView alloc] init];
        [_redView setBackgroundColor:[UIColor redColor]];

    }
    return _redView;
}

 4.2 左右排列

   //左左排列核心思想:起点blueView固定中心、左右,高度及等宽,中间redView固定高度,中心及右边,最右边视图等高,右,中心位置
    CGFloat padding = 10.0f;
    [self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view.mas_left).offset(padding);
        make.centerY.equalTo(self.view.mas_centerY);
        make.height.equalTo(@50);
        make.width.equalTo(@[self.redView,self.yellowView]);
        make.right.equalTo(self.redView.mas_left).with.offset(-padding);
    }];
    [self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@50);
        make.right.equalTo(self.yellowView.mas_left).offset(-padding);
        make.centerY.equalTo(self.view.mas_centerY);
    }];
    [self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(@[self.blueView,self.redView]);
        make.height.equalTo(@[self.blueView,self.redView]);

        make.right.equalTo(self.view.mas_right).offset(-10);
    }];

 4.3 上下复合排列

    //左右下核心思想,首先总体结构是上下所以要设置等高,然后再设置上下左右的间隙,左1设置上左下右及高度,右1设置右下上就可以因为左边已经有约束,下blueView只需要设置左右下及高度
    CGFloat padding = 10.0f;
    [self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.top.equalTo(self.view).insets(UIEdgeInsetsMake(padding, padding, 0, 0));
        make.right.equalTo(self.redView.mas_left).offset(-padding);
        make.bottom.equalTo(self.blueView.mas_top).offset(-padding);
        make.width.equalTo(self.redView.mas_width);
    }];
    [self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.right.equalTo(self.view).insets(UIEdgeInsetsMake(padding, 0,0,padding));
        make.bottom.equalTo(self.blueView.mas_top).offset(-padding);
    }];
    [self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(0, padding, 0, padding));
        make.bottom.equalTo(self.view.mas_bottom);
        make.height.equalTo(self.yellowView.mas_height);
    }];

 4.4 约束比例, multipliedBy 只能设置同一控制的,如自身高度等于宽度的3倍,宽度*这个比例

 UIView *topView = [[UIView alloc] init];
    topView.backgroundColor = [UIColor redColor];
    [self.view addSubview:topView];

    UIView *topInnerView = [[UIView alloc] init];
    topInnerView.backgroundColor = [UIColor greenColor];
    [topView addSubview:topInnerView];

    UIView *bottomView = [[UIView alloc] init];
    bottomView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:bottomView];

    UIView *bottomInnerView = [[UIView alloc] init];
    bottomInnerView.backgroundColor = [UIColor blueColor];
    [bottomView addSubview:bottomInnerView];

    [topView mas_makeConstraints:^(MASConstraintMaker *make) {~~
        make.left.right.top.equalTo(self.view).width.offset(0);
        make.height.mas_equalTo(bottomView);
    }];
    [topInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(topView);

        make.width.equalTo(topInnerView.mas_height).multipliedBy(3);
           make.center.equalTo(topView);
        //设置优先级,设置优先级时一定要加(),优先级 Masonry会优先实现优先级高的设定,发生冲突时,放弃优先级低的设定.
        make.width.height.mas_equalTo(topView).priorityLow();
        make.width.height.lessThanOrEqualTo(topView);
    }];
    [bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.bottom.equalTo(self.view);
        make.top.equalTo(topView.mas_bottom);

    }];
    [bottomInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.mas_equalTo(bottomView);
        make.center.equalTo(bottomView);
        make.height.equalTo(bottomInnerView.mas_width).multipliedBy(3);
        //设置优先级,lessThanOrEqualTo小于等于,优先级 Masonry会优先实现优先级高的设定,发生冲突时,放弃优先级低的设定.
        make.height.width.equalTo(bottomView).priorityLow();
        make.height.width.lessThanOrEqualTo(bottomView);

    }];

4.5 点击放大,更新约束的使用

 /**3.点击放大,知识点,更新约束,优先级,小于等于等
     核心1://初始化宽度,高为100,优先级最低
     make.width.height.mas_equalTo(100*self.scale).priorityLow();
     //最大放大到整个view,小于等于view的宽度和高度
     make.width.height.lessThanOrEqualTo(self.view);
     核心2:更新约束 ,告诉需要更新,检查是否需要更新,立即更新*/
@property (nonatomic, strong) UIButton *bigButton;
@property (nonatomic, assign) CGFloat scale;//比例

    self.scale = 1.0;
    self.bigButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.bigButton setTitle:@"点我放大" forState:UIControlStateNormal];
    self.bigButton.layer.borderColor = UIColor.greenColor.CGColor;
    self.bigButton.layer.borderWidth = 3;
    [self.bigButton addTarget:self action:@selector(onGrowButtonTaped:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.bigButton];

    [self.bigButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.mas_equalTo(self.view);
        //初始化宽度,高为100,优先级最低
        make.width.height.mas_equalTo(100*self.scale).priorityLow();
        //最大放大到整个view
        make.width.height.lessThanOrEqualTo(self.view);
    }];
#pragma mark - ??event response
- (void)onGrowButtonTaped:(UIButton *)sender{
    self.scale += 0.2;
    //告诉self.view约束需要更新
    [self.view setNeedsUpdateConstraints];
    // 调用此方法告诉self.view检测是否需要更新约束,若需要则更新,下面添加动画效果才起作用
    [self.view updateConstraintsIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded]; //立即更新
    }];
}
#pragma mark - updateViewConstraints
- (void)updateViewConstraints{

    [self.bigButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);

        //设置优先级
        make.width.height.mas_equalTo(100*self.scale).priorityLow();
        make.width.height.lessThanOrEqualTo(self.view);
    }];
    //调用父类更新约束
    [super updateViewConstraints];
}

4.6 scrollView的简单适配

   /**4. scrollView,核心思想就是先固定四周,然后再设置contentSize,在这里是底部
     核心1:preferredMaxLayoutWidth 最大的适配宽度
     核心2:scrollView的适配,首先先固定,然后设置底部的值
     核心3:配置label顶部间距
     */
    self.scrollView = [[UIScrollView alloc] init];
    self.scrollView.pagingEnabled = NO;
    [self.view addSubview:self.scrollView];
    [self.scrollView setBackgroundColor:[UIColor lightGrayColor]];
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    UILabel *lastLabel = nil;
    for (NSInteger i = 0; i < 20; i++) {
        UILabel *label = [[UILabel alloc] init];
        label.numberOfLines = 0;
        label.layer.borderColor = [UIColor greenColor].CGColor;
        label.layer.borderWidth = 2.0;
        label.text = [self ranomText];
        label.preferredMaxLayoutWidth = screenWidth - 30;
        label.textAlignment = NSTextAlignmentLeft;
        [self.scrollView addSubview:label];

        [label mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.view.mas_left).offset(15);
            make.right.equalTo(self.view.mas_right).offset(-15);
            if (lastLabel) {//下一行是第一行最后一个label加上一定的间距
                make.top.mas_equalTo(lastLabel.mas_bottom).offset(20);
            }else{
                make.top.mas_equalTo(self.scrollView.mas_top).offset(20);
            }

        }];
        lastLabel = label;
    }
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
        make.bottom.equalTo(lastLabel.mas_bottom).offset(20);
    }];
#pragma mark - ??private
- (NSString *)ranomText{

    CGFloat length = arc4random()%50 +5;
    NSMutableString *str = [[NSMutableString alloc] init];
    for (NSInteger i = 0; i <length; i++) {
        [str appendString:@"测试一下啦!"];
    }
    return str;
}  

 

 

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #008f00 }
span.s1 { }
span.s2 { font: 11.0px Menlo }

时间: 2024-10-13 05:50:39

masonry 学习笔记 一(基础尝试)的相关文章

大话设计模式学习笔记——面向对象基础

前言 好记性不如烂"笔头"系列--大话设计模式学习笔记 目录 面向对象基础 面向对象基础 什么是类与实例 一切事物皆为对象,即所有的东西老师对象,对象就是可以看到.感觉到.听到.触摸到.尝到.或闻到的东西.准确地说,对象是一个自包含的实体,用一组可识别的特性和行为来标识.面向对象编程,英文叫 Object-Oriented Programming,其实就是针对对象来进行编程的意思.类就是具有相同属性和功能的对象的抽象集合.实例就是一个真实的对象.比如我们属于'人'类,而个人就是'人'类

Java快速教程--vamei 学习笔记(基础篇)

链接:http://www.cnblogs.com/vamei/archive/2013/03/31/2991531.html java快速教程第1课 从HelloWorld到面向对象 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/14/2958654.html java快速教程第2课 方法与数据成员 学习网址:http://www.cnblogs.com/vamei/archive/2013/03/25/2964430.html java快

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字节的值,该如何在它上面调用方法? 二:值类型转换为引用类型--装箱 2.1CLR对值类型进行装箱时:新分配托管堆内存,将值类型的实例字段拷贝到新分配的内存中,返回托管堆中新分配对象的地址.这个地址就是一个指向对象的引用. int i = 10; Object obj = i; 三:将引用类型转换为值

[Golong]学习笔记(一) 基础知识

Go编程基础 Go的内置关键字(25个) 不多 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continute for import return var Go的注释方法(和js一样) 单行注释: // 多行注释: /**/ Go程序一般结构 common_structure.go 通过 pack

01-Python学习笔记-基础语法

Python标识符 -d           在解析时显示调试信息 -O           生成优化代码 ( .pyo 文件 ) -S           启动时不引入查找Python路径的位置 -v            输出Python版本号 -X           从 1.6版本之后基于内建的异常(仅仅用于字符串)已过时. -c cmd     执行 Python 脚本,并将运行结果作为 cmd 字符串. file           在给定的python文件执行python脚本. P

PHP:学习笔记(2)——基础语法

PHP:学习笔记(2)--基础语法 向屏幕输出 说明 1.void echo ( string $arg1 [, string $... ] ) 2.int print ( string $arg ) 注意: 1.echo.print 实际上不是一个函数(它是一个语言结构),因此你可以不必使用圆括号来括起它的参数列表. 2.输出变量的时候需要使用双引号! 3.int printf ( string $format [, mixed $args [, mixed $... ]] ) 4.strin

jQuery学习笔记——jQuery基础核心

代码风格 在jQuery程序中,不管是页面元素的选择.内置的功能函数,都是美元符号“$”来起始的.而这个“$”就是jQuery当中最重要且独有的对象:jQuery对象,所以我们在页面元素选择或执行功能函数的时候可以这么写: $(function () {}); //执行一个匿名函数 $(‘#box’);//进行执行的ID元素选择 $(‘#box’).css(‘color’, ‘red’);//执行功能函数由于$本身就是jQuery对象的缩写形式,那么也就是说上面的三段代码也可以写成如下形式:jQ

OpenFlow Switch学习笔记(一)——基础概念

OpenFlow Switch v1.4.0规范是在2013年10月14号发布,规范涵盖了OpenFlow Switch各个组件的功能定义.Controller与Switch之间的通信协议Open Flow Protocol等.下文主要是基于个人理解整理的一些学习笔记,理解不到位的地方还请大家多多指教. 一.基础概念图: 首先我们先看下Open Flow Switch的整体结构,以便有一个初步的感性认识,如下图所示: 从上面架构图中,我们可以看到Open Flow Switch主要是由以下几个部

.net学习笔记---xml基础知识

一.XML简介 XML是一种标记语言,用于描述数据,它提供一种标准化的方式来来表示文本数据.XML文档以.xml为后缀.需要彻底注意的是XML是区分大小写的. 先从一个简单的XML例子来了解下xml基础: <?xml version="1.0" encoding="utf-8" ?> <books ISBN="9787544238212"> <title>xml学习笔记</title> <pr

C#学习笔记(基础知识回顾)之枚举

一:枚举的含义 枚举是用户定义的整数类型.在声明一个枚举时,要指定该枚举的示例可以包含的一组可接受的值.还可以给值指定易于记忆的名称.个人理解就是为一组整数值赋予意义. 二:枚举的优势 2.1:枚举可以使代码更易于维护,有助于确保给变量指定合法的.期望的值. 2.2:枚举可以使代码清晰,用描述性的名称来表示整数值,增加代码可读性. 三:枚举的使用 /// <summary> /// 声明一个枚举,审核状态 /// </summary> public enum AduitStatus