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
  • 相关阅读:
    HDU 1269 迷宫城堡
    HDU 4771 Stealing Harry Potter's Precious
    HDU 4772 Zhuge Liang's Password
    HDU 1690 Bus System
    HDU 2112 HDU Today
    HDU 1385 Minimum Transport Cost
    HDU 1596 find the safest road
    HDU 2680 Choose the best route
    HDU 2066 一个人的旅行
    AssetBundle管理机制(下)
  • 原文地址:https://www.cnblogs.com/sundaysgarden/p/9061170.html
Copyright © 2011-2022 走看看