zoukankan      html  css  js  c++  java
  • Masonry中的mas_makeConstraints方法

    一、简单介绍

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

    [objc] view plain copy
    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.     }];  
    然后我们先看看其内部的方法
    [objc] view plain copy
    1. - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {  
    2.       
    3.     self.translatesAutoresizingMaskIntoConstraints = NO;  
    4.       
    5.     //创建MASConstraintMaker对象,就是我们block中的make,  
    6.     MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];  
    7.       
    8.     //执行block  
    9.     block(constraintMaker);  
    10.       
    11.     //安装install 约束  
    12.     return [constraintMaker install];  
    13. }  

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZCMUCZX/article/details/79908462
  • 相关阅读:
    R语言实战(四)回归
    nginx无法启动: libpcre.so.1/libpcre.so.0: cannot open shared object file解决办法
    nginx无法启动: libpcre.so.1/libpcre.so.0: cannot open shared object file解决办法
    nginx无法启动: libpcre.so.1/libpcre.so.0: cannot open shared object file解决办法
    nginx无法启动: libpcre.so.1/libpcre.so.0: cannot open shared object file解决办法
    Debian安装fail2ban来防止扫描
    Debian安装fail2ban来防止扫描
    Debian安装fail2ban来防止扫描
    Debian安装fail2ban来防止扫描
    字典转Json
  • 原文地址:https://www.cnblogs.com/sundaysgarden/p/9061170.html
Copyright © 2011-2022 走看看