zoukankan      html  css  js  c++  java
  • masonry 使用笔记

    Masonry的使用,动画,出现问题解决等

    经过一点时间的使用,发现在网上很少有Masonry的教程,也仅仅有那么一两篇而已,在此我编写一下我最近一段时间使用的方法,供大家学习。

    Masonry是AutoLayout的一个第三方类库,用链式语法封装了冗长的AutoLayout代码,因此学习成本相对于官方提供的AutoLayout,以及VFL语言而言,低上很多很多...

    准备

    在GitHub上 https://github.com/SnapKit/Masonry 下载配置第三方库,基本使用方法在Readme中也有说明,我就不赘述了,CocoaPods在我blog有相关的设置介绍 CocoaPods的安装使用

    pod 'Masonry'

    为了方便更新库来解决旧有bug,所以不写版本号 '~>x.x.x'

    在pch文件中加入

    #import "Masonry.h"

    便可全局使用

    基本用法

    可以理解和Android五大布局中的相对布局一样,基本原理就是本控件相对于某个控件的位置,因此相对比较需要有一个参考控件

    基本的计算公式为

    控件左边 = 参考控件的右边 + 偏移值(5) (控件在参考控件的右边,距离其5px)

    make.left.equalTo(view.superview.mas_right).offset(10);//不填则默认对应left,其他同理

    支持的属性

    @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有三种设置约束的方法

    mas_makeConstraints //第一次生成约束使用
    
    mas_updateConstraints    //更新其中的约束
    
    mas_remakeConstraints    //重新生成约束,会将之前的所有约束先去掉

    使用注意:在循环cell,如果有代码重复调用的地方,一定要使用mas_remakeConstraints,以此防止循环的时候生成相同的约束,影响性能,甚至,能使用make的地方基本都可以用remake进行代替,防止生成无谓的约束

    简单用法

    初始化一个带边距的view

    UIView *view = [[UIView alloc] init];
    
    view.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:view];//一定要先加入父控件,否则报错
    
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.edges.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));
    
    }];

    等价

    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.left.right.top.bottom.equalTo(view.superview).insets(UIEdgeInsetsMake(20, 20, 20, 20));

    left ,right等属性,如字面意思

    等价

    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.left.equalTo(view.superview).offset(20);
    
    make.top.equalTo(view.superview).offset(20);
    
    make.right.equalTo(view.superview).offset(-20);
    
    make.bottom.equalTo(view.superview).offset(-20);
    
    }];

    链式语法中,and 以及 with都是修饰性语句,不做任何事情,便于理解而已

    make.bottom.and.top.equalTo(view.superview).with.offset(-20);

    源码中

    #pragma mark - Semantic properties
    
    - (MASConstraint *)with {
    
    return self;
    
    }
    
    - (MASConstraint *)and {
    
    return self;
    
    }

    间隔View

    子控件宽高为父控件的一半(multipliedBy)

    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.left.equalTo(view.superview);
    
    make.top.equalTo(view.superview).offset(20);
    
    make.width.height.equalTo(view.superview).multipliedBy(0.5);
    
    }];

    这里写图片描述

    大于小于

    make.width.greaterThanOrEqualTo(@200);
    
    make.width.lessThanOrEqualTo(@400)

    blcok中进行判断使用约束(在统一处理某些业务的时候)

    [self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
    
    make.size.equalTo(self.buttonSize);
    
    if (topLeft) {
    
    make.top.and.left.offset(10);
    
    } else {
    
    make.bottom.and.right.offset(-10);
    
    }
    
    }];死高度300 * 300

    修改指定约束

    MASConstraint *topConstraint;
    
    // 在生成约束的时候
    
    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    
    topConstraint = make.top.equalTo(superview.mas_top);
    
    make.left.equalTo(superview.mas_left);
    
    }];
    
    ...
    
    // 在之后进行对该约束 进行修改
    
    [topConstraint uninstall];

    写死高度300 * 300

    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.center.equalTo(view.superview);
    
    make.width.height.equalTo(@300);
    
    }];

    关于mas_equalTo使用

    Masonry表示相等有两种方法,equalTo 和 mas_equalTo

    mas_equalTo其实是多了一层处理的宏而已,因为equalTo并不支持基本数据类型

    #define mas_equalTo(...)                equalTo(MASBoxValue((__VA_ARGS__)))

    在高度为300的约束中,可以这样子写

    mak.height.equalTo(@300);

    也可以,使用mas_equalTo,一般情况下,我会全部使用mas_equalTo来处理基本数据类型的封装

    mak.height.mas_equalTo(300);

    并列排序-水平 或者 高度

    经常会遇到很多需要等宽或者登高排序的需求,下面是我个人使用的一种方法,可以参考一下,但是需要说明的是,相对布局的各种用法很多,请思考便可以,同一种效果,N种写法

    - (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //都是相对于suerpview来设置位置的
    
    NSMutableArray *viewArray = [NSMutableArray array];
    
    NSArray *colorArray = @[[UIColor redColor],[UIColor blueColor],[UIColor orangeColor],[UIColor purpleColor]];
    
    for (int i = 0; i < colorArray.count ; i++) {
    
    UIView *view = [[UIView alloc] init];
    
    view.backgroundColor = colorArray[i];
    
    [self.view addSubview:view];
    
    [viewArray addObject:view];
    
    }
    
    [self sortVerticalWithViews:viewArray LeftMargin:50 Width:100 BackViewHeight:300];
    
    viewArray = [NSMutableArray array];
    
    for (int i = 0; i < colorArray.count ; i++) {
    
    UIView *view = [[UIView alloc] init];
    
    view.backgroundColor = colorArray[i];
    
    [self.view addSubview:view];
    
    [viewArray addObject:view];
    
    }
    
    [self sortHorizontalWithViews:viewArray TopMargin:320 TopView:self.view Height:100];
    
    }
    
    #pragma mark 将控件进行排序,更新其操作(水平)
    
    - (void)sortHorizontalWithViews:(NSArray *)views TopMargin:(NSInteger)topMargin TopView:(UIView *)topView Height:(NSInteger)viewH
    
    {
    
    __block UIView *leftView;
    
    [views enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    
    UIView *tempView = obj;
    
    [tempView mas_remakeConstraints:^(MASConstraintMaker *make) {
    
    if (idx == 0) {
    
    make.left.equalTo(tempView.superview);
    
    if ([topView isEqual:tempView.superview]) { //如果传入的是容器view 则上方无控件
    
    make.top.mas_equalTo(topView).offset(topMargin);
    
    } else {
    
    make.top.mas_equalTo(topView.mas_bottom).offset(topMargin);
    
    }
    
    make.width.mas_equalTo(tempView.superview.mas_width).multipliedBy((CGFloat)1 / views.count);
    
    make.height.mas_equalTo(viewH);
    
    } else {
    
    make.left.equalTo(leftView.mas_right);
    
    make.top.mas_equalTo(leftView);
    
    make.width.mas_equalTo(leftView);
    
    make.height.equalTo(leftView);
    
    }
    
    }];
    
    leftView = tempView;
    
    }];
    
    }
    
    #pragma mark 将控件进行排序,更新其操作(垂直)
    
    - (void)sortVerticalWithViews:(NSArray *)views LeftMargin:(NSInteger)leftMargin Width:(NSInteger)viewWidth BackViewHeight:(NSInteger)backViewHeight
    
    {
    
    __block UIView *topView;
    
    [views enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    
    UIView *tempView = obj;
    
    [tempView mas_remakeConstraints:^(MASConstraintMaker *make) {
    
    if (idx == 0) {
    
    make.left.equalTo(tempView.superview).offset(leftMargin);
    
    make.top.mas_equalTo(tempView.superview);
    
    make.width.mas_equalTo(viewWidth);
    
    make.height.mas_equalTo(backViewHeight / views.count);
    
    } else {
    
    make.left.equalTo(topView);
    
    make.top.mas_equalTo(topView.mas_bottom);
    
    make.width.mas_equalTo(topView);
    
    make.height.mas_equalTo(topView);
    
    }
    
    }];
    
    topView = tempView;
    
    }];
    
    }

    这里写图片描述

    动画问题

    动画问题,和普通的方法实现差不多,重点只是修改约束后调用

    [view.superview layoutIfNeeded];

    而已

    [view mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.top.mas_equalTo(400);
    
    make.left.mas_equalTo(100);
    
    make.size.mas_equalTo(CGSizeMake(100, 100));
    
    }];
    
    [view.superview layoutIfNeeded];//如果其约束还没有生成的时候需要动画的话,就请先强制刷新后才写动画,否则所有没生成的约束会直接跑动画
    
    [UIView animateWithDuration:3 animations:^{
    
    [view mas_updateConstraints:^(MASConstraintMaker *make) {
    
    make.left.mas_equalTo(200);
    
    }];
    
    [view.superview layoutIfNeeded];//强制绘制
    
    }];

    遇到的问题

    AutoLayout是在iOS7 之后才刚刚推出的一种新的方法,因为在iOS7系统上并不能算得上十分完善,经常有一些bug,然而在iOS8中相对好的处理了

    最明显的问题就是scorllView的contentSize问题

    系统的约束并不是在设置完成之后里面进行绘图的,而是在最后ViewDidApper()这个函数前一些时间才完成绘图,而且每次绘制(比如,往 scorllView上添加新的子控件,即增加了新的约束)后,scorllView的contentOffset和contentSize都会初始化为 0,因此每次都需要重新设置(如果你在绘制前已经设置了contentSize的话),或者你可以使用tableView来代替scorllView

    - (void)viewDidAppear:(BOOL)animated
    
    {
    
    [super viewDidAppear:animated];
    
    _scorllView.contentSize = CGSizeMake(200, 200);
    
    }

    如果你需要在约束设置完成后立马得到frame的数值的话,调用

    [view.superview layoutIfNeeded];

    之后会强制性更新约束,这句话之后便可以得到frame,在iOS8中只需要在这加入设置contentSize便可以实现正常的scrollView滚动,而iOS7中则不可以,请注意。

    而且如果出现什么疑难杂症的话,基本都是AutoLayout在iOS的不适用,所以搜索问题的话,各位直接搜索Autolayout 关键字便可,不必搜索Masonry关键字的问题(反正也搜不到什么答案...)

     
  • 相关阅读:
    rabbimq连接问题处理
    svn小设置
    日志的乱码,以及数据库编码问题
    Intellij Idea 14 使用jetty-maven-plugin配置运行web工程
    心血来潮
    maven nexus 私服的搭建学习
    致成长——毕业一周年
    2015-7-2
    我的JQuery复习笔记之①——text(),html(),val()的区别
    【转】title与alt的区别
  • 原文地址:https://www.cnblogs.com/canghaixiaoyuer/p/4943619.html
Copyright © 2011-2022 走看看