Masonry 自动布局 及注意点

TIPS: 如有错误之处欢迎批评指正

使用Masonry,通过代码来进行布局

  • equalto 和 mas_equalto 是有区别的。但是我们不打算去了解,可以通过添加以下代码来统一。
    • 注意!! 宏定义必须要放在 import 引入头文件之前!
//define this constant if you want to use Masonry without the 'mas_' prefix
#define MAS_SHORTHAND
//define this constant if you want to enable auto-boxing for default syntax
#define MAS_SHORTHAND_GLOBALS

#import "Masonry.h"
  • 使用masonry的步骤及注意点。先来看下面这段代码

    • 进行约束的 self.SelChildView必须已经被addView添加过。也就是说必须已经有父类了,否则报错
    • make.top .bottom .left .right .等等方向equalTo后面()的内容

    必须是一个CGFloat,如果是和某个view有关系,调用的时候不能直接用mv.openDrawerButton.bottom,必须用mv.openDrawerButton.mas_bottom
    • make.size .width .height等等尺寸equalTo后面()的内容
      必须是一个具体的CGFloat数,不能用 mas_width 等等,否则会 上面的IBAction不响应
    • 如果出现IBAction无响应,多半是make.size/width/height的约束没做好
    • with和and都是一个宏,可以查看他,其实就是一个return self
    self.SelChildView = [[UISegmentedControl alloc] initWithItems:@[@"蓝牙连接",@"WiFi连接"]];
    [self.view addSubview:self.SelChildView];
    // add constrains
    [self.SelChildView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(48.0f);
        make.top.equalTo(mv.openDrawerButton.mas_bottom).with.offset(8.0f);
        make.centerX.equalTo(mv.view。mas_centerX);
        make.left.equalTo(mv.view).with.offset(8.0f);
        make.right.equalTo(mv.view).with.offset(-8.0f);
        make.width.equalTo(self.SelChildView.frame.size.width);//直接用equalTo(self.SelChildView.mas_width)可能会导致SelChildView上面的控件失效
        make.height.equalTo(self.SelChildView.frame.size.height);//直接用equalTo(self.SelChildView.mas_height)可能会导致SelChildView上面的控件失效
    }];
  • 使用masonry进行约束创建的尺寸,并不等于你已经创建了他的frame!
    • 我们来解释下下面这张图。


    • 如果我们不写 frame的那句,而用make.size.equalTo(CGSizeMake(5,5)); 我们看到的效果是一样的。

但是!如果这样做了,是无法获取到他的frame的值的。通过打印他的x,y,width,height会发现是0

  • 使用masonry的实质还是调用了ios7以后的autolayout,如果要升级frame,必须在最后增加一句
[self.currentView.superview layoutIfNeeded];//打印他的frame发现已经更新

使用和不使用Masonry下的尺寸问题

  • 比如说,[[UIView alloc] initWithFrame],这个frame的大小是 5x5的大小。
    然后我insert一个image,大小是30x30,最后显示的时候,我们看到的图片是30x30的
  • 缩放比例,只能通过改变他的长宽来实现,不能用 multipliedBy 来实现等比例缩放,不知道是什么原因!! 坑掉过一次就不要忘记!!
  • 等比例缩放的实例:
    [self.openDrawerButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).with.offset(20.0f);
        make.left.equalTo(self.view).with.offset(11.0f);
        // 等比例缩小 0.8
        CGSize size = CGSizeMake(0.8*self.openDrawerButton.frame.size.width, 0.8*self.openDrawerButton.frame.size.height);
        make.size.mas_equalTo(size);//如果添加了宏定义,这里可以不用mas_
    }];

Masonry 实例,分别约束代码创建和 XIB / Storyboard 创建的UIView

Demo 中讨论了masonry配合实现动画时候碰见的四种情形,分别是:

trytry.gif
序号 Masonry 纯Frame XIB 纯代码 可行动画 备注
1 ✔️ ✔️ 卷轴/平移 不使用masonry,通过纯代码和frame 创建卷轴动画/平移动画
2 ✔️ ✔️ 卷轴/平移 尝试通过masonry+纯代码方式创建卷轴动画/平移,用masonry来升级 frame
3 ✔️ ✔️ 平移/横向缩放 通过XIB创建DIYView + frame创建平移动画,证明无法使用卷轴动画。因为尺寸不可变(width可变,height不行)
4 ✔️ ✔️ 平移/横向缩放 通过XIB创建DIYView + masonry 创建平移动画和卷轴动画(width可变,height不行),用masonry来升级 frame

下面是四个情形的代码

TIPS: 说明下使用masonry升级frame,形成动画的注意点:

  • mas_makeConstrains之后,在后面要加上 [self.viewX.superview layoutIfNeeded]; 升级frame
  • 动画中调用mas_updateConstrains升级他的约束,然后也要调用一次[self.viewX.superview layoutIfNeeded]; 升级frame
  • 如果约束的是XIB的DIYView,masonry的约束可能和XIB中的约束冲突,如果使用缩放,注意make.size的值要设置好,否则可能IBAction失效
    // Step 1, 通过纯代码和frame 创建卷轴动画/平移动画
    self.View1 = [[UIView alloc] initWithFrame:CGRectMake(0,200, [UIScreen mainScreen].bounds.size.width, 0)];
    self.View1.backgroundColor = [UIColor greenColor];
    UILabel* lb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
    lb.text = @"TTY";
    [self.view addSubview:self.View1];
    // 动画
    [UIView animateWithDuration:10.0
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:^{
                         self.View1.frame = CGRectMake(0, 200, [UIScreen mainScreen].bounds.size.width, 80);
                         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                             [self.View1 addSubview:lb];
                         });
                     }
                     completion:^(BOOL finished) {
                     }];
    // Step 2, 尝试通过masonry+纯代码方式创建卷轴动画,用masonry来升级 frame
    self.View2 = [[UIView alloc] init];
    self.View2.backgroundColor = [UIColor blackColor];
    [self.view addSubview:self.View2];
    
    [self.View2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(300);
        make.left.mas_equalTo(100);
        make.size.mas_equalTo(CGSizeMake(100, 100));
    }];
    NSLog(@"masonry 之前size = %f,%f",self.View2.frame.size.width,self.View2.frame.size.height);
    [self.View2.superview layoutIfNeeded];
    
    [UIView animateWithDuration:10.0
                     animations:^{
                         [self.View2 mas_updateConstraints:^(MASConstraintMaker *make) {
                             make.left.mas_equalTo(200);
                         }];
                         [self.View2.superview layoutIfNeeded];
                     }];
    NSLog(@"masonry 之后size = %f,%f",self.View2.frame.size.width,self.View2.frame.size.height);
// step 3 通过XIB创建DIYView + frame创建滚动动画,证明无法使用卷轴动画。因为尺寸不可变(宽度可以用屏幕宽度赋值,除此其他不行),只能使用滚动动画
    self.View3 = [[NSBundle mainBundle] loadNibNamed:@"BossView"
                                               owner:self
                                             options:nil].lastObject;
    CGRect view3rect = CGRectMake([UIScreen mainScreen].bounds.size.width, 400, [UIScreen mainScreen].bounds.size.width, self.View3.frame.size.height);
    self.View3.frame = view3rect;
    [self.view addSubview:self.View3];
    [UIView animateWithDuration:5.0
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:^{
                         CGRect view3rect = CGRectMake(0, 400, [UIScreen mainScreen].bounds.size.width, self.View3.frame.size.height);
                         self.View3.frame = view3rect;
                     } completion:^(BOOL finished) {
                     }];

    // step 4 通过XIB创建DIYView + masonry 创建滚动动画和卷轴动画(宽度可以改,长度不能改)
    self.View4 = [[NSBundle mainBundle] loadNibNamed:@"BossView"
                                               owner:self
                                             options:nil].lastObject;
    
    [self.view addSubview:self.View4];
    [self.View4 mas_makeConstraints:^(MASConstraintMaker *make) {
        CGSize realsize = CGSizeMake(self.View4.bounds.size.width,0 );
        make.size.equalTo(realsize);
        make.top.equalTo(self.view.mas_top).with.offset(600);
        make.centerX.equalTo(self.view.mas_centerX);
    }];
    [self.View4.superview layoutIfNeeded];
    NSLog(@"View4 masonry 之后size = %f,%f",self.View4.frame.size.width,self.View4.frame.size.height);
    [UIView animateWithDuration:10
                     animations:^{
                         [self.View4 mas_updateConstraints:^(MASConstraintMaker *make) {
                             CGSize realsize = CGSizeMake([UIScreen mainScreen].bounds.size.width, self.View4.bounds.size.height);
                             make.size.equalTo(realsize);
                         }];
                         [self.View4.superview layoutIfNeeded];
                     }];

---- 2018.7.12 补充

从渲染的帧率来看,使用约束进行布局实质上是会比较消耗资源的。
尤其是使用上文提到的 使用 masonry 进行动画

举一个例子,我们经常用到的 IM 类场景(如 QQ,微信)这种高开销的 tableView。聊天的内容在不断刷新,滑动后会加载新的头像,内容等等。如果使用约束布局,势必面临着重新渲染的情况。

这时候帧率 的卡顿会成为一个比较大的问题。

从经验上来总结,大开销的场景下,动画和渲染,还是使用原始的frame布局来做。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 一、前言 关于苹果的布局一直是我比较纠结的问题,是写代码来控制布局,还是使用storyboard来控制布局呢?以前...
    iplaycodex阅读 2,442评论 0 1
  • iOS_autoLayout_Masonry 概述 Masonry是一个轻量级的布局框架与更好的包装AutoLay...
    指尖的跳动阅读 1,155评论 1 4
  • Masonry和FDTemplateLayoutCell搭配使用总结 http://www.jianshu.com...
    动感超人丶阅读 74评论 0 0
  • 5月5日全国各地同期上映的印度电影《摔跤吧,爸爸》获得了几乎所有影评人和观影者的一致好评,这部励志电影是根据印度国...
    凹现场阅读 262评论 0 3
  • 姓名:陆振村~公司:浙江均泰建设有限公司 【日精进打卡第47天】 【知~学习】 《六项精进》大纲0遍 共64遍 《...
    陆振村阅读 253评论 0 0