Masonry中的mas_makeConstraints方法
一、简单介绍
我们一般来说会这样进行使用
- [view mas_makeConstraints:^(MASConstraintMaker *make) {
- //这个使用的就是MASCompositeConstraint类型的
- make.left.top.width.height.mas_equalTo(100).multipliedBy(1);
- //这个使用的就是单个单个的MASViewConstraint
- // make.left.mas_equalTo(100);
- // make.top.mas_equalTo(100);
- // make.width.mas_equalTo(100);
- // make.height.mas_equalTo(100);
- }];
然后我们先看看其内部的方法
- - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
- self.translatesAutoresizingMaskIntoConstraints = NO;
- //创建MASConstraintMaker对象,就是我们block中的make,
- MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
- //执行block
- block(constraintMaker);
- //安装install 约束
- return [constraintMaker install];
- }
我们再去看看install的方法,其内部就是去先去获取view的所有的约束,然后进行移除,之后再去安装新的约束
- - (NSArray *)install {
- //判断是否要移除已经存在的约束,这里其实就是在使用re_make的时候这个会为YES
- if (self.removeExisting) {
- //获取view的所有的约束
- 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;
- }
这个时候大家肯定很疑惑,What? 我约束都还没有添加,怎么直接开始遍历了? 其实我们在block中执行make.left.width这个时候其实就已经在添加约束了,先来看下在调用.left的时候调用的MASConstraintMaker的方法
返回值是MASConstriant,所以我们在make.left之后再.width其实是调用的是MASConstraint的width方法了其中这个方法是个抽象方法定义在MASConstraint类中。
然后之后调用的就是MASViewConstraint中的addConstraintWithLayoutAttribute方法
然后我们点进上面的self.delegate 调用的方法进去看看,调用的是下面的方法,这里其实就可以理解为把left和Width的约束进行合并成为一个约束集合类
- - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
- //根据layoutAttribute属性也就是NSLayoutAttributeTop这些初始化MASViewAttribute类
- MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
- //根据viewAttribute创建MASViewConstraint对象
- MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
- //如果有constraint的话,就进行合并成一个composite Constraint,这个是一个集合类
- if ([constraint isKindOfClass:MASViewConstraint.class]) {
- //replace with composite constraint
- NSArray *children = @[constraint, newConstraint];
- /*
- MASCompositeConstraint:约束的集合类。内部有一个数组,可以保存多个MASViewConstraint。对MASCompositeConstraint调用方法实际等于
- 对其内部的所有MASViewConstraint调用方法
- */
- MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
- compositeConstraint.delegate = self;
- //在self.constraint进行替换
- [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
- return compositeConstraint;
- }
- //如果不存在constraint那就去设置newConstraint,然后添加进入约束数组
- if (!constraint) {
- newConstraint.delegate = self;
- //add
- [self.constraints addObject:newConstraint];
- }
- return newConstraint;
- }
再去看看constraintMaker中的install方法中的NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];里面的installedConstraintsForView方法内部调用了mas_installedConstraints的get方法,然后去获取所有的对象,也就是这里面的方法
- + (NSArray *)installedConstraintsForView:(MAS_VIEW *)view {
- return [view.mas_installedConstraints allObjects];
- }
再去看看这个get方法其实就是运用了运行时的知识
- - (NSMutableSet *)mas_installedConstraints {
- NSMutableSet *constraints = objc_getAssociatedObject(self, &kInstalledConstraintsKey);
- if (!constraints) {
- constraints = [NSMutableSet set];
- //相当于 setValue:forKey 进行关联value对象
- objc_setAssociatedObject(self, &kInstalledConstraintsKey, constraints, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- return constraints;
- }
然后再去看看关于uninstall方法的实现,这个方法的实现就是先判断能不能相应active方法,因为这个属性是ios8才出现的
- - (void)uninstall {
- if ([self supportsActiveProperty]) {
- //设置约束不可用
- self.layoutConstraint.active = NO;
- //移除约束
- [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
- return;
- }
- //来到下面表示不能响应active方法,做了适配
- [self.installedView removeConstraint:self.layoutConstraint];
- self.layoutConstraint = nil;
- self.installedView = nil;
- [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
- }
我们再去看看安装新约束当中的install方法
- - (void)install {
- //判断约束是否已经存在,以及是否已经处理激活状态其实就是使用状态
- if (self.hasBeenInstalled) {
- return;
- }
- //判断布局是否可以响应active这个方法的设置,判断layoutConstriant存不存在
- if ([self supportsActiveProperty] && self.layoutConstraint) {
- //iOS 6.0或者7.0调用addConstraints
- //[self.view addConstraints:@[leftConstraint, rightConstraint, topConstraint, heightConstraint]];
- //iOS 8.0以后设置active属性值 就可以去使用约束了
- self.layoutConstraint.active = YES;
- //这里会进行添加约束
- [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
- return;
- }
- //获取item,获取第一个viewattribute的item也就是constraintWithItem中的item
- MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
- //获取属性比如说NSLayoutAttributeTop
- NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
- //获取约束的第二个view
- MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
- //获取layout的属性
- NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
- // alignment attributes must have a secondViewAttribute
- // therefore we assume that is refering to superview
- // eg make.left.equalTo(@10)
- //判断是不是要设置的是size的约束,以及判断第二个约束的属性是不是为空如果为空,就去设置下面的属性
- if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
- secondLayoutItem = self.firstViewAttribute.view.superview;
- secondLayoutAttribute = firstLayoutAttribute;
- }
- //创建约束布局 self.layoutRelation就是约束关系
- MASLayoutConstraint *layoutConstraint
- = [MASLayoutConstraint constraintWithItem:firstLayoutItem
- attribute:firstLayoutAttribute
- relatedBy:self.layoutRelation
- toItem:secondLayoutItem
- attribute:secondLayoutAttribute
- multiplier:self.layoutMultiplier
- constant:self.layoutConstant];
- //设置约束的优先级
- layoutConstraint.priority = self.layoutPriority;
- /*
- 当约束冲突发生的时候,我们可以设置view的key来定位是哪个view
- redView.mas_key = @"redView";
- greenView.mas_key = @"greenView";
- blueView.mas_key = @"blueView";
- 若是觉得这样一个个设置比较繁琐,怎么办呢,Masonry则提供了批量设置的宏MASAttachKeys
- MASAttachKeys(redView,greenView,blueView); //一句代码即可全部设置
- */
- layoutConstraint.mas_key = self.mas_key;
- //判断第二个view是否存在
- 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;
- }
- //如果是设置view的宽度和高度的,设置安装越苏的视图为第一个view
- else if (self.firstViewAttribute.isSizeAttribute) {
- self.installedView = self.firstViewAttribute.view;
- }
- //否则就给superview进行设置
- else {
- self.installedView = self.firstViewAttribute.view.superview;
- }
- MASLayoutConstraint *existingConstraint = nil;
- //判断是否是更新约束,这里判断的条件就是是否只存在constant不一样的视图
- if (self.updateExisting) {
- existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
- }
- //如果已经存在只有constant不一样的约束,就去更新constant
- if (existingConstraint) {
- // just update the constant
- existingConstraint.constant = layoutConstraint.constant;
- self.layoutConstraint = existingConstraint;
- }
- //如果没有存在的只有constant不一样的约束,就去添加约束
- else {
- [self.installedView addConstraint:layoutConstraint];
- self.layoutConstraint = layoutConstraint;
- [firstLayoutItem.mas_installedConstraints addObject:self];
- }
- }
关于上面判断是否只存在constant不一样的视图的方法
- - (MASLayoutConstraint *)layoutConstraintSimilarTo:(MASLayoutConstraint *)layoutConstraint {
- // check if any constraints are the same apart from the only mutable property constant
- // go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
- // and they are likely to be added first.
- //从后面往前面遍历这个数组
- for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
- if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
- if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
- if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
- if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
- if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
- if (existingConstraint.relation != layoutConstraint.relation) continue;
- if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
- if (existingConstraint.priority != layoutConstraint.priority) continue;
- return (id)existingConstraint;
- }
- return nil;
- }
关于self.hasBeenInstalled其实就是调用了下面的方法
- - (BOOL)hasBeenInstalled {
- return (self.layoutConstraint != nil) && [self isActive];
- }
其实Masonry就是对系统本身的自动布局的layout进行了封装
Masonry中的mas_makeConstraints方法的更多相关文章
- 【问题】Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数
[问题]Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数. [解决]直接对变量加引号,如: <button onclick="deleteProduct('@ ...
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- 为什么不能在init和dealloc函数中使用accessor方法
前言 为什么不要在init和dealloc方法中调用getter和setter:Apple在Mac与iOS中关于内存管理的开发文档中,有一节的题目为:"Don'tUse Accessor M ...
- C#中DataTable中的Compute方法使用收集
原文: C#中DataTable中的Compute方法使用收集 Compute函数的参数就两个:Expression,和Filter. Expresstion是计算表达式,关于Expression的详 ...
- C#中的扩展方法
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方 ...
- C#中的匿名方法
C#中的匿名方法是在C#2.0引入的,它终结了C#2.0之前版本声明委托的唯一方法是使用命名方法的时代.虽然在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方 ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- 什么情况下才要重写Objective-C中的description方法
特别注意: 千万不要在description方法中同时使用%@和self,同时使用了%@和self,代表要调用self的description方法,因此最终会导致程序陷入死循环,循环调用descrip ...
- PHP中常见魔术方法解析
<?php class info { private $province; //省 public $city; //城市 private $myname; //姓名 //__construct( ...
随机推荐
- ExtJS:Grid数据导出至excel实例
导出函数ExportExcel() var config={ store: alldataStore, title: '测试标题' }; var tab=tabPanel.getActiveTab() ...
- SVN版本控制器中各符号的含义
SVN符号的含义 项目开发过程中,随着学习的不断深入,开始慢慢接触到版本管理控制工具,其实这个工具主要用于团队开发之中,但对于个人项目的备份也有好处,可以避免在电脑出现不可预知的故障时,最大化的保护自 ...
- C++中重载、覆盖与隐藏的区别(转)
本文摘自林锐博士的<高质量C++/C编程指南>. 成员函数的重载.覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚概念,否则错误将防不胜防. 1.重载与覆盖 成员函数被重 ...
- 第一个Polymer应用 - (3)使用数据绑定
原文链接: Step 3: Using data binding翻译日期: 2014年7月7日翻译人员: 铁锚我们创建的个人信息卡还算漂亮,但对整个应用来说,只有一张卡片看起来有点空荡荡的感觉.在本节 ...
- XMPP系列(三)---获取好友列表、添加好友
1.心跳检测.掉线重连功能 客户端和服务器端都可以设置多久发送一次心跳包,如果对方没有返回正确的pong信息,则会断开连接,而添加掉线重连功能,则会自动进行连接. 如果自己写聊天功能还得自己做心跳检测 ...
- javac编译同一个包内的java文件
问题描述:包a.b.c里有d.java e.java f.java三个文件,其中d中包含main. 错误: 第一种:javac d.java 报错:里面用到其他类,找不到 第二种:javac *.ja ...
- 恶补web之八:jQuery(1)
jquery是一个js库,极大的简化了js编程.jquery是一个写的更少,但做的更多的轻量级js库. jquery位于一个js文件中,其中包含了所有jquery函数,可以用如下标记把jquery添加 ...
- LambdaToSql 发布 兰姆达转换sql
文档目录索引 查询.函数.分组.排序.分页 添加 Insert into 编辑 Update set 删除 Delete 生成实体 内置常用工具类库 文档完善中... 事务处理 Join 连接查询 ...
- Spring Boot定时任务应用实践
在Spring Boot中实现定时任务功能,可以通过Spring自带的定时任务调度,也可以通过集成经典开源组件Quartz实现任务调度. 一.Spring定时器 1.cron表达式方式 使用自带的定时 ...
- css3属性(1)
text-transform语法: text-transform : none | capitalize| uppercase| lowercase 参数: none : 无转换发生 capitali ...