2018年04月12日 10:10:54

阅读数:138

一、简单介绍

我们一般来说会这样进行使用

  1. [view mas_makeConstraints:^(MASConstraintMaker *make) {
  2. //这个使用的就是MASCompositeConstraint类型的
  3. make.left.top.width.height.mas_equalTo(100).multipliedBy(1);
  4. //这个使用的就是单个单个的MASViewConstraint
  5. //            make.left.mas_equalTo(100);
  6. //            make.top.mas_equalTo(100);
  7. //            make.width.mas_equalTo(100);
  8. //            make.height.mas_equalTo(100);
  9. }];

然后我们先看看其内部的方法

  1. - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
  2. self.translatesAutoresizingMaskIntoConstraints = NO;
  3. //创建MASConstraintMaker对象,就是我们block中的make,
  4. MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
  5. //执行block
  6. block(constraintMaker);
  7. //安装install 约束
  8. return [constraintMaker install];
  9. }

我们再去看看install的方法,其内部就是去先去获取view的所有的约束,然后进行移除,之后再去安装新的约束

  1. - (NSArray *)install {
  2. //判断是否要移除已经存在的约束,这里其实就是在使用re_make的时候这个会为YES
  3. if (self.removeExisting) {
  4. //获取view的所有的约束
  5. NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
  6. for (MASConstraint *constraint in installedConstraints) {
  7. [constraint uninstall];
  8. }
  9. }
  10. //安装新约束
  11. NSArray *constraints = self.constraints.copy;
  12. for (MASConstraint *constraint in constraints) {
  13. constraint.updateExisting = self.updateExisting;
  14. [constraint install];
  15. }
  16. [self.constraints removeAllObjects];
  17. return constraints;
  18. }

这个时候大家肯定很疑惑,What? 我约束都还没有添加,怎么直接开始遍历了? 其实我们在block中执行make.left.width这个时候其实就已经在添加约束了,先来看下在调用.left的时候调用的MASConstraintMaker的方法

返回值是MASConstriant,所以我们在make.left之后再.width其实是调用的是MASConstraint的width方法了其中这个方法是个抽象方法定义在MASConstraint类中。

然后之后调用的就是MASViewConstraint中的addConstraintWithLayoutAttribute方法

然后我们点进上面的self.delegate 调用的方法进去看看,调用的是下面的方法,这里其实就可以理解为把left和Width的约束进行合并成为一个约束集合类

  1. - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
  2. //根据layoutAttribute属性也就是NSLayoutAttributeTop这些初始化MASViewAttribute类
  3. MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
  4. //根据viewAttribute创建MASViewConstraint对象
  5. MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
  6. //如果有constraint的话,就进行合并成一个composite Constraint,这个是一个集合类
  7. if ([constraint isKindOfClass:MASViewConstraint.class]) {
  8. //replace with composite constraint
  9. NSArray *children = @[constraint, newConstraint];
  10. /*
  11. MASCompositeConstraint:约束的集合类。内部有一个数组,可以保存多个MASViewConstraint。对MASCompositeConstraint调用方法实际等于
  12. 对其内部的所有MASViewConstraint调用方法
  13. */
  14. MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
  15. compositeConstraint.delegate = self;
  16. //在self.constraint进行替换
  17. [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
  18. return compositeConstraint;
  19. }
  20. //如果不存在constraint那就去设置newConstraint,然后添加进入约束数组
  21. if (!constraint) {
  22. newConstraint.delegate = self;
  23. //add
  24. [self.constraints addObject:newConstraint];
  25. }
  26. return newConstraint;
  27. }

再去看看constraintMaker中的install方法中的NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];里面的installedConstraintsForView方法内部调用了mas_installedConstraints的get方法,然后去获取所有的对象,也就是这里面的方法

  1. + (NSArray *)installedConstraintsForView:(MAS_VIEW *)view {
  2. return [view.mas_installedConstraints allObjects];
  3. }

再去看看这个get方法其实就是运用了运行时的知识

  1. - (NSMutableSet *)mas_installedConstraints {
  2. NSMutableSet *constraints = objc_getAssociatedObject(self, &kInstalledConstraintsKey);
  3. if (!constraints) {
  4. constraints = [NSMutableSet set];
  5. //相当于 setValue:forKey 进行关联value对象
  6. objc_setAssociatedObject(self, &kInstalledConstraintsKey, constraints, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  7. }
  8. return constraints;
  9. }

然后再去看看关于uninstall方法的实现,这个方法的实现就是先判断能不能相应active方法,因为这个属性是ios8才出现的

  1. - (void)uninstall {
  2. if ([self supportsActiveProperty]) {
  3. //设置约束不可用
  4. self.layoutConstraint.active = NO;
  5. //移除约束
  6. [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
  7. return;
  8. }
  9. //来到下面表示不能响应active方法,做了适配
  10. [self.installedView removeConstraint:self.layoutConstraint];
  11. self.layoutConstraint = nil;
  12. self.installedView = nil;
  13. [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
  14. }

我们再去看看安装新约束当中的install方法

  1. - (void)install {
  2. //判断约束是否已经存在,以及是否已经处理激活状态其实就是使用状态
  3. if (self.hasBeenInstalled) {
  4. return;
  5. }
  6. //判断布局是否可以响应active这个方法的设置,判断layoutConstriant存不存在
  7. if ([self supportsActiveProperty] && self.layoutConstraint) {
  8. //iOS 6.0或者7.0调用addConstraints
  9. //[self.view addConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]];
  10. //iOS 8.0以后设置active属性值 就可以去使用约束了
  11. self.layoutConstraint.active = YES;
  12. //这里会进行添加约束
  13. [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
  14. return;
  15. }
  16. //获取item,获取第一个viewattribute的item也就是constraintWithItem中的item
  17. MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
  18. //获取属性比如说NSLayoutAttributeTop
  19. NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
  20. //获取约束的第二个view
  21. MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
  22. //获取layout的属性
  23. NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
  24. // alignment attributes must have a secondViewAttribute
  25. // therefore we assume that is refering to superview
  26. // eg make.left.equalTo(@10)
  27. //判断是不是要设置的是size的约束,以及判断第二个约束的属性是不是为空如果为空,就去设置下面的属性
  28. if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
  29. secondLayoutItem = self.firstViewAttribute.view.superview;
  30. secondLayoutAttribute = firstLayoutAttribute;
  31. }
  32. //创建约束布局 self.layoutRelation就是约束关系
  33. MASLayoutConstraint *layoutConstraint
  34. = [MASLayoutConstraint constraintWithItem:firstLayoutItem
  35. attribute:firstLayoutAttribute
  36. relatedBy:self.layoutRelation
  37. toItem:secondLayoutItem
  38. attribute:secondLayoutAttribute
  39. multiplier:self.layoutMultiplier
  40. constant:self.layoutConstant];
  41. //设置约束的优先级
  42. layoutConstraint.priority = self.layoutPriority;
  43. /*
  44. 当约束冲突发生的时候,我们可以设置view的key来定位是哪个view
  45. redView.mas_key = @"redView";
  46. greenView.mas_key = @"greenView";
  47. blueView.mas_key = @"blueView";
  48. 若是觉得这样一个个设置比较繁琐,怎么办呢,Masonry则提供了批量设置的宏MASAttachKeys
  49. MASAttachKeys(redView,greenView,blueView); //一句代码即可全部设置
  50. */
  51. layoutConstraint.mas_key = self.mas_key;
  52. //判断第二个view是否存在
  53. if (self.secondViewAttribute.view) {
  54. //寻找两个视图的公共父视图,这个方法其实就是循环遍历寻找
  55. MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
  56. //断言判断公共父视图存不存在
  57. NSAssert(closestCommonSuperview,
  58. @"couldn't find a common superview for %@ and %@",
  59. self.firstViewAttribute.view, self.secondViewAttribute.view);
  60. //设置安装约束的视图
  61. self.installedView = closestCommonSuperview;
  62. }
  63. //如果是设置view的宽度和高度的,设置安装越苏的视图为第一个view
  64. else if (self.firstViewAttribute.isSizeAttribute) {
  65. self.installedView = self.firstViewAttribute.view;
  66. }
  67. //否则就给superview进行设置
  68. else {
  69. self.installedView = self.firstViewAttribute.view.superview;
  70. }
  71. MASLayoutConstraint *existingConstraint = nil;
  72. //判断是否是更新约束,这里判断的条件就是是否只存在constant不一样的视图
  73. if (self.updateExisting) {
  74. existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
  75. }
  76. //如果已经存在只有constant不一样的约束,就去更新constant
  77. if (existingConstraint) {
  78. // just update the constant
  79. existingConstraint.constant = layoutConstraint.constant;
  80. self.layoutConstraint = existingConstraint;
  81. }
  82. //如果没有存在的只有constant不一样的约束,就去添加约束
  83. else {
  84. [self.installedView addConstraint:layoutConstraint];
  85. self.layoutConstraint = layoutConstraint;
  86. [firstLayoutItem.mas_installedConstraints addObject:self];
  87. }
  88. }

关于上面判断是否只存在constant不一样的视图的方法

  1. - (MASLayoutConstraint *)layoutConstraintSimilarTo:(MASLayoutConstraint *)layoutConstraint {
  2. // check if any constraints are the same apart from the only mutable property constant
  3. // go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
  4. // and they are likely to be added first.
  5. //从后面往前面遍历这个数组
  6. for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
  7. if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
  8. if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
  9. if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
  10. if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
  11. if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
  12. if (existingConstraint.relation != layoutConstraint.relation) continue;
  13. if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
  14. if (existingConstraint.priority != layoutConstraint.priority) continue;
  15. return (id)existingConstraint;
  16. }
  17. return nil;
  18. }

关于self.hasBeenInstalled其实就是调用了下面的方法

  1. - (BOOL)hasBeenInstalled {
  2. return (self.layoutConstraint != nil) && [self isActive];
  3. }

其实Masonry就是对系统本身的自动布局的layout进行了封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZCMUCZX/article/details/79908462

Masonry中的mas_makeConstraints方法的更多相关文章

  1. 【问题】Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数

    [问题]Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数. [解决]直接对变量加引号,如: <button onclick="deleteProduct('@ ...

  2. java 执行 jar 包中的 main 方法

    java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...

  3. 为什么不能在init和dealloc函数中使用accessor方法

    前言 为什么不要在init和dealloc方法中调用getter和setter:Apple在Mac与iOS中关于内存管理的开发文档中,有一节的题目为:"Don'tUse Accessor M ...

  4. C#中DataTable中的Compute方法使用收集

    原文: C#中DataTable中的Compute方法使用收集 Compute函数的参数就两个:Expression,和Filter. Expresstion是计算表达式,关于Expression的详 ...

  5. C#中的扩展方法

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方 ...

  6. C#中的匿名方法

    C#中的匿名方法是在C#2.0引入的,它终结了C#2.0之前版本声明委托的唯一方法是使用命名方法的时代.虽然在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方 ...

  7. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  8. 什么情况下才要重写Objective-C中的description方法

    特别注意: 千万不要在description方法中同时使用%@和self,同时使用了%@和self,代表要调用self的description方法,因此最终会导致程序陷入死循环,循环调用descrip ...

  9. PHP中常见魔术方法解析

    <?php class info { private $province; //省 public $city; //城市 private $myname; //姓名 //__construct( ...

随机推荐

  1. How tomcat works 读书笔记十七 启动tomcat 上

    一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...

  2. 解决Cell重用内容混乱的几种简单方法,有些方法会增加内存

    重用实现分析 查看UITableView头文件,会找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells两个结构 ...

  3. 爬虫Scrapy框架运用----房天下二手房数据采集

    在许多电商和互联网金融的公司为了更好地服务用户,他们需要爬虫工程师对用户的行为数据进行搜集.分析和整合,为人们的行为选择提供更多的参考依据,去服务于人们的行为方式,甚至影响人们的生活方式.我们的scr ...

  4. JMM规范

    JMM规范: The rules for happens-before are: Program order rule. Each action in a thread happens-before ...

  5. 利用LinkedHashMap实现简单的缓存

    update1:第二个实现,读操作不必要采用独占锁,缓存显然是读多于写,读的时候一开始用独占锁是考虑到要递增计数和更新时间戳要加锁,不过这两个变量都是采用原子变量,因此也不必采用独占锁,修改为读写锁. ...

  6. 关于期权池Option Pools与Vesting:码农创业防身必备法器

    之前又看到饿了么创始人团队纠纷的几篇文章,参考了百科.wiki.36Kr.虎嗅.知乎以及邵亦波老师的文章,对之前一直感兴趣的期权汇编初略总结了下 ,仍觉粗糙,对一些具体操作还是不甚了了,不过感觉在中国 ...

  7. 推荐Python、Django中文文档地址

    协作翻译网:http://usyiyi.cn/ 老牌的Python中文社区:http://woodpecker.org.cn/ The Django Book2.0中文版:http://djangob ...

  8. 走进netty

    三月份开始看公司RPC框架的源码,发现如果要折腾明白,网络通讯这块知识必不可少.于是从如下几点开始逐步研究. 一.基础知识篇 1.Unix下5种I/O模型 Linux的内核将所有外部设备都看作一个文件 ...

  9. SQL基本语句的优化10个原则

    原则一:尽量避免在列上进行运算,这样会导致索引失效. 例如: ; 优化: SELECT * FROM table WHERE d >= '2011-01-01'; 原则二:使用JOIN时,应该用 ...

  10. C#学习笔记 day_two

    C#学习笔记 day two Chapter 2 c#基本概念 2.1编译与运行hello world应用程序 点击f5或者vs2010中的运行图标即可 2.3C#的概念拓展 (1)继承性:一个类含有 ...