背景

iOS平台上Autolayout布局对于屏幕的适配简直就是一把利剑,如果用xib或Storyboard进行布局对于每个人来说肯定是得心应手。不过如果对于纯代码布局的人来说,使用苹果苹果原生的api写过的人都知道是非常复杂的。所以Masonry横空出世,此框架主要是针对苹果Autolayout原生代码的封装,通过链式调用的方式,大大简化了使用复杂度,老少兼宜! 接下来就让我们分析一下它是如何封装的呢?

架构图

首先让我们对于架构图做个简要说明 相对来说Masonry一共分为三层。

  • View+MASAdditions:第一层.提供最外层make、update、remake三个主要方法创建约束;并且提供了获取约束的方法。
  • MASConstraintMaker:第二层。提供一个桥梁的作用,也是核心作用。我们生产的所有约束均存在此类的一个数组里。当调用install方法的时候,会循环遍历数组
  • MASConstraint:第三层。这个是两个子类的父类,是Masonry约束的载体,并且拥有一个MASViewAttribute类的对象,用于存储苹果Autolayout的载体和真正作用的视图。

MASCompositeConstraint此子类主要是针对make.width.height这种链式调用,通过数组的形式存储了多个约束条件。也即多个MASViewConstraint此类对象。所以MASCompositeConstraint这个类的操作最终还是调用了MASViewConstraint这个类内的方法。

源码解析

[redView mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(superview.mas_top).with.offset(padding);
}];
复制代码

注意:以上代码不是一个视图的完整约束。我们分析只要通过一个约束解析就好,代码处理逻辑都是一样的 这个代码我们调用的一个创建约束的最外层api,接下来让我们进去看看它里边的实现。

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {self.translatesAutoresizingMaskIntoConstraints = NO;MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];block(constraintMaker);return [constraintMaker install];
}
复制代码

这里实例化了一个constraintMaker供我们上层api的使用,通过调用block,执行了我们创建约束的代码,然后调用install方法,最终完成了视图约束的创建。

接下来让我分两步分析这里边的核心实现。

  • make.top.equalTo(superview.mas_top).with.offset(padding);这个代码的实现完成了约束对象的创建

  • [constraintMaker install]完成了最终我们创建的约束对应作用于视图

make.top.equalTo(superview.mas_top).with.offset(padding);解析

这个点语法,每次调用要不就是创建了一个约束,要不就是更改约束的值

我们首先来看make.top

- (MASConstraint *)top {return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}
复制代码

这个方法比较简单,主要是对api的调用,并且传入了NSLayoutAttributeTop苹果层面约束的名称

接下来让我们看约束添加的核心方法,所有添加约束的方法都是调用此方法

- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];if ([constraint isKindOfClass:MASViewConstraint.class]) {//replace with composite constraintNSArray *children = @[constraint, newConstraint];MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];compositeConstraint.delegate = self;[self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];return compositeConstraint;}if (!constraint) {newConstraint.delegate = self;[self.constraints addObject:newConstraint];}return newConstraint;
}
复制代码

这个方法有两个分支,一个是传入nil,也是目前我们分析的情况,另外一种情况我们稍后展开分析,其实就是make.width.height这种连续的情况,此时不会出入nil的。 言归正传,当出入nil的时候,首先实例化了viewAttributenewConstraint两个变量。viewAttribute此变量持有作用的视图和约束名称,newConstraintMasonry层面的约束,实现约束的具体逻辑。 其次设置了delegate,并且加入了constraints数组中。这个数组存储了所有的约束对象。最后返回了newConstraint对象

make.top至此已经分析结束,接着我们看make.top.equalTo(superview.mas_top)。这个方法我们最应该学习的,这个方法设计的也比较巧妙。第一回看可能不知道这个语法是怎么回事呢。接下来让我们看看MASConstraint类中的equalTo方法的实现。

- (MASConstraint * (^)(id))equalTo {return ^id(id attribute) {return self.equalToWithRelation(attribute, NSLayoutRelationEqual);};
}
复制代码

这个方法是返回了一个block,所以.equalTo()括号调用的就是block执行。block返回MASConstraint *一个对象。

接着让我们看看MASViewConstraint.offset()方法

- (void)setOffset:(CGFloat)offset {self.layoutConstant = offset;
}
复制代码

这个方法比较简单,只是给MASViewConstraint对象设置了一个具体的值。

到此这个方法已经分析完成。

接下来让我们看看上边提到的另一种调用方式make.width.height

这种调用我们就不一一展开分析了,主要我们来看.height,调用这个方法的时候会执行上文说的- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute中以下代码

if ([constraint isKindOfClass:MASViewConstraint.class]) {//replace with composite constraintNSArray *children = @[constraint, newConstraint];MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];compositeConstraint.delegate = self;[self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];return compositeConstraint;
}
复制代码

这里是实例化了MASConstraint另外一个子类MASCompositeConstraint,这个类其实很简单,就是用来存储多个MASViewConstraint对象,然后循环遍历操作每个对象

[constraintMaker 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;
}
复制代码

这个方法就是一个循环遍历的操作。不过[constraint install];这个方法会调用MASViewConstraint的install和MASCompositeConstraint的install。

MASViewConstraint的install

- (void)install {if (self.hasBeenInstalled) {return;}if ([self supportsActiveProperty] && self.layoutConstraint) {self.layoutConstraint.active = YES;[self.firstViewAttribute.view.mas_installedConstraints addObject:self];return;}MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;// alignment attributes must have a secondViewAttribute// therefore we assume that is refering to superview// eg make.left.equalTo(@10)if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {secondLayoutItem = self.firstViewAttribute.view.superview;secondLayoutAttribute = firstLayoutAttribute;}MASLayoutConstraint *layoutConstraint= [MASLayoutConstraint constraintWithItem:firstLayoutItemattribute:firstLayoutAttributerelatedBy:self.layoutRelationtoItem:secondLayoutItemattribute:secondLayoutAttributemultiplier:self.layoutMultiplierconstant:self.layoutConstant];layoutConstraint.priority = self.layoutPriority;layoutConstraint.mas_key = self.mas_key;if (self.secondViewAttribute.view) {MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];NSAssert(closestCommonSuperview,@"couldn't find a common superview for %@ and %@",self.firstViewAttribute.view, self.secondViewAttribute.view);self.installedView = closestCommonSuperview;} else if (self.firstViewAttribute.isSizeAttribute) {self.installedView = self.firstViewAttribute.view;} else {self.installedView = self.firstViewAttribute.view.superview;}MASLayoutConstraint *existingConstraint = nil;if (self.updateExisting) {existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];}if (existingConstraint) {// just update the constantexistingConstraint.constant = layoutConstraint.constant;self.layoutConstraint = existingConstraint;} else {[self.installedView addConstraint:layoutConstraint];self.layoutConstraint = layoutConstraint;[firstLayoutItem.mas_installedConstraints addObject:self];}
}
复制代码

这个方法则是针对maker的2种情况调用了苹果底层api,进行约束的创建。分别是更新约束和重新创建约束。

MASCompositeConstraint的install

- (void)install {for (MASConstraint *constraint in self.childConstraints) {constraint.updateExisting = self.updateExisting;[constraint install];}
}
复制代码

此方法就是将存储的MASViewConstraintMASCompositeConstraint对象,循环遍历调用上述的intall方法。如果是MASCompositeConstraint对象对象,则会递归调用。

总结

Masonry整个架构还是比较简单的,值的我们学习的一方面是它的整个架构设计,另一方面很值得我们学习的是在OC中如何实现链式调用

我的博客

FlyOceanFish

iOS之Masonry代码解析相关推荐

  1. iOS第三方-Masonry使用技巧

    Masonry使用技巧 masonry git地址:https://github.com/SnapKit/Masonry 本文主要会讲到masonry英文文档(见上面的git地址)中提及到的使用说明, ...

  2. IOS之Masonry约束的使用

    IOS之Masonry约束的使用 Masonry是做约束的,类似苹果开发的约束,做屏幕的适配,有xib开发,纯代码开发,storyboard约束等其他第三方框架. pod 加入 pod 'Masonr ...

  3. iOS - - JSON 和 XML解析

    JSON 和 XML 一.JSON 1.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) 2.JSON的格 ...

  4. 视频直播美颜SDK算法代码解析

    随着短视频.直播软件一类app的流行,美颜sdk的应用也越来越广泛.所谓"美颜",简单解释下,就是通过视频(图片)技术对人脸进行美化.但是就"美化"这个词,却牵 ...

  5. react-native-art path代码解析

    React-Native-ART代码解析 一.探寻源码 1.如何使用 安卓自己集成,不需要额外操作,iOS需要pod添加ART库,如下: pod 'React', :path => '../rn ...

  6. matrix_multiply代码解析

    matrix_multiply代码解析 关于matrix_multiply 程序执行代码里两个矩阵的乘法,并将相乘结果打印在屏幕上. 示例的主要目的是展现怎么实现一个自定义CPU计算任务. 参考:ht ...

  7. CornerNet代码解析——损失函数

    CornerNet代码解析--损失函数 文章目录 CornerNet代码解析--损失函数 前言 总体损失 1.Heatmap的损失 2.Embedding的损失 3.Offset的损失 前言 今天要解 ...

  8. 视觉SLAM开源算法ORB-SLAM3 原理与代码解析

    来源:深蓝学院,文稿整理者:何常鑫,审核&修改:刘国庆 本文总结于上交感知与导航研究所科研助理--刘国庆关于[视觉SLAM开源算法ORB-SLAM3 原理与代码解析]的公开课. ORB-SLA ...

  9. java获取object属性值_java反射获取一个object属性值代码解析

    有些时候你明明知道这个object里面是什么,但是因为种种原因,你不能将它转化成一个对象,只是想单纯地提取出这个object里的一些东西,这个时候就需要用反射了. 假如你这个类是这样的: privat ...

  10. python中的doc_基于Python获取docx/doc文件内容代码解析

    这篇文章主要介绍了基于Python获取docx/doc文件内容代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 整体思路: 下载文件并修改后缀 ...

最新文章

  1. Oracle Sales Cloud 实施(二)
  2. SQL Loader 的使用详解
  3. Python之多进程
  4. 爬虫进行request请求时User-Agent怎样写
  5. iOS Cookie相关操作
  6. 链计算:构建信任网络,致力无边界协同
  7. C#学习(6)——LINQ学习
  8. 坐异性朋友的车时,能坐在副驾驶吗?
  9. C# 正则表达式 匹配IP地址
  10. Java EnumMap工作原理及实现
  11. 听音扒谱app_掌握这些,你也可以轻松扒谱(下)
  12. 10、【易混淆概念集】-第六章1 三点估算 类比估算和参数估算的区别 储备分析 历时估算 项目进度网络图
  13. 详解浅拷贝,深拷贝及实现方法
  14. openlayers实现地图显示功能
  15. 二项式展开推广与微积分的关系
  16. RouterOS 重置密码
  17. 优格筑家 引领高档家装!
  18. 计算机组成原理是答案,计算机组成原理(上)_答案mooc
  19. 免费空间如何建设网站?
  20. hnust 2186 C 层次遍历

热门文章

  1. Hadoop 删除节点步骤
  2. 为什么我推荐ImageJ?
  3. 【opencv+C++】在图像中找四边形
  4. OpenCV2 图像叠加 给照片加水印
  5. 【VS2010学习笔记】【函数学习】一(VC6.0和VS2010主函数的不同)
  6. 从零基础入门Tensorflow2.0 ----九、44.5 keras转换成具体函数
  7. matlab-读取文件
  8. 并发编程之美(1)并发编程基础二
  9. 深度系统优化工具_HiBit Uninstaller卸载工具【win版】
  10. SQL 中的 in 与 not in、exists 与 not exists 的区别以及性能分析