iOS进阶之Masonry

iOS进阶之masonry细致入微(二)

2019-01-08  本文已影响0人  天蓬大元
在上篇文章中,我们了解到,当为某一个view添加约束时,masonry的代码执行顺序是下面这样的。我们通过细致的分析了解到一条约束在被装载到view之前,masonry都做了什么。其他三个约束的处理亦然。
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);

^(MASConstraintMaker *make) {
    make.left.mas_equalTo(lable.superview.mas_left).offset(10);
    make.right.mas_equalTo(-10);
    make.top.mas_equalTo(0);
    make.bottom.mas_equalTo(0);
}

return [constraintMaker install];
我们这篇文章主要讲述,如何将存储在MASConstraintMaker对象中的约束装载到view上。在开始之前,我们简短的回顾一个约束的收集过程。
1,创建一个MASConstraintMaker类对象爱丽丝,她持有要添加约束view乔治,并且持有一个数组,用来收集约束。
2,爱丽丝通过.left创建一个MASViewConstraint类对象葛二蛋,葛二蛋持有了left约束条件,并被保存在爱丽丝的数组中。
3,葛二蛋通过mas_equalTo获取到相对于父类的约束并存储
4,葛二蛋通过offset获取到子类与父类约束之间的改变值。
.right和.top和.bottom的处理情况与.left类似。
至此,葛二蛋兄弟4个持有了乔治所有的约束条件,而爱丽丝持有了乔治和葛二蛋兄弟4个。那接下来就是爱丽丝如何将二蛋四兄弟装载到乔治身上,完成约束的添加任务。
好,我们开始进入正题:[constraintMaker install]。
 - (NSArray *)install {
    ///注意这里的self指代的是谁。
    ///这个是干什么的,我们先不管,你只要知道这里if的代码不会被执行
    if (self.removeExisting) {
        NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
        for (MASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    ///你不应该还不知道这里的self是谁。
    NSArray *constraints = self.constraints.copy;
    for (MASConstraint *constraint in constraints) {
        ///取出来的就是二蛋4兄弟之一
        constraint.updateExisting = self.updateExisting;
        ///调用了葛二蛋的装载方法。
        [constraint install];
    }
    ///爱丽丝的数组被清空,但constraints仍然保存了一份二蛋4兄弟。这里你应该知道copy的用法。体会这里作者为什么用copy处理一下数组。
    [self.constraints removeAllObjects];
    ///返回了二蛋4兄弟,注意,此时爱丽丝没有再持有这四兄弟。
    return constraints;
}
不要着急,我们掰开了一个一个看。
二蛋的装载 [constraint install];
- (void)install {
    ///如果已经被装载,则不需要重复装载
    if (self.hasBeenInstalled) {
        return;
    }
    这个我们先不管
    if ([self supportsActiveProperty] && self.layoutConstraint) {
        self.layoutConstraint.active = YES;
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
        return;
    }

    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    ///这个是要添加约束的view的自己的约束项
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    ///这个是相对于父视图的约束项
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

    // alignment attributes must have a secondViewAttribute
    // therefore we assume that is refering to superview
    // eg make.left.equalTo(@10)
    ///这里作者的注释已经写的很清楚了,如果你写出了make.left.equalTo(@10)这样的约束,就会用到这个处理,自动获取父类,并让父类的对比约束和子类一样。
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        ///父类
        secondLayoutItem = self.firstViewAttribute.view.superview;
        ///父类的约束条件取子类的约束条件
        secondLayoutAttribute = firstLayoutAttribute;
    }
    ///好,接下来的代码就是核心中的核心了。调用系统的autolayout进行约束处理。MASLayoutConstraint继承自NSLayoutConstraint。扩展了一个有意思的key,你能体会到这个key的用处吗?如果你不数熟悉autolayout的API,记得了解一下,这里不做过多解释。你可以不用,但你最好知道。
    MASLayoutConstraint *layoutConstraint
    = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                    attribute:firstLayoutAttribute
                                    relatedBy:self.layoutRelation
                                       toItem:secondLayoutItem
                                    attribute:secondLayoutAttribute
                                   multiplier:self.layoutMultiplier
                                     constant:self.layoutConstant];
    ///其实看到这里,你就应该思索,masonry的功能,不仅仅是添加普通约束。
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;
    ///这个是干什么的?
    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);
        ///关键理解这个。这里还是要说,你真的需要理解一下autolayout是如何进行布局的。公共父类进行布局约束。
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        /**///了解了这个,就好理解这里的判断了。
            - (BOOL)isSizeAttribute {
                    return self.layoutAttribute == NSLayoutAttributeWidth
    || self.layoutAttribute == NSLayoutAttributeHeight;
            }
        */
        self.installedView = self.firstViewAttribute.view;
    } else {
        ///view相对于view.superView进行布局
        self.installedView = self.firstViewAttribute.view.superview;
    }


    MASLayoutConstraint *existingConstraint = nil;
    ///更新或新增约束
    if (self.updateExisting) {
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) {
        // just update the constant
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}
到这里,整个装载过程就完成了。但我相信,你还没有很好的理解整个装载过程。不要心急。这个过程只是引导大家对masonry做常用最简单的一个约束过程有一个大致的了解。接下来,我将以这次装载过程为线索,详细的去理一理这个框架的脉络和文件,对源码进行逐行的分析。我相信,有了前面这个简单的了解,我们对于后面的理解会容易得多。
上一篇下一篇

猜你喜欢

热点阅读