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. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  2. 苹果IOS与谷歌 android系统的UI设计原则

    一.苹果为IOS的界面设计提出了六大原则: 1.整体美学 整体美学指的是一个应用的表现和行为与它的功能完美集成,传达连贯的信息. 人们关心一个应用是否提供它承诺的功能,但他们也被应用的外观和行为强烈影 ...

  3. C语言之回文数算法

    "回文"是指正读反读都能读通的句子,它是古今中外都有的一种修辞方式和文字游戏,如"我为人人,人人为我"等.在数学中也有这样一类数字有这样的特征,成为回文数(pa ...

  4. Android Data Binding代码实践(告别findViewById)(四)

    Data Binding实战(一) Data Binding语法解析(二) Data Binding高级用法(三) 好了,继前三篇学习了Data Binding之后,我们可以发现它的强大之处有这么几点 ...

  5. TCP连接建立系列 — TCP选项解析

    本文主要分析:在收到客户端的SYN包时,服务器端是如何解析它所携带的TCP选项,并结合本端情况决定是否予以支持. 内核版本:3.6 Author:zhangskd @ csdn blog 概述 收到客 ...

  6. How to download the installation package by ZOL Downer

    How to download the installation package by ZOL Downer Ma Genfeng (Guangdong Unitoll Services incorp ...

  7. 如何在os x或ubuntu下安装最新的ruby

    os x下基本上可以安装到比较新的ruby,首先先安装rvm,然后用rvm list known看当前可供安装的ruby的版本,不过这也不是绝对的,比如在我的os x 10.9上,命令返回如下: # ...

  8. 基于hashchange导航管理

    想在五一放假的时候写出来,由于放假有点兴奋,心早就跑了,不废话了. 说一下基于hashchange导航管理: 浏览器的历史记录导航是用户非常常用的功能,除了点击前进后退按钮外,Window上的hist ...

  9. Eclipse常见设置

    当新建一个workspace时,习惯做下面的设置: 1. 在eclipse中,默认的Text file encoding是GBK(操作系统是中文简体):如果操作系统是中文繁体,默认是MS950(Big ...

  10. solr研磨之性能调优

    作者:战斗民族就是干  转载请注明地址:http://www.cnblogs.com/prayers/p/8982141.html 本篇文章我们来了解一下solr的性能方面的调优,分为Schema优化 ...