AutoLayout 之 读一读Masonry的源码

AutoLayout 之 读一读Masonry的源码

第一次写博客 怀着一颗认真的心 开始

Masonry 是如何实现链式调用的

先看一段代码

UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 200, 100)];
    bgView.backgroundColor = [UIColor redColor];
    [self.view addSubview:bgView];
    **subView是bgView的子视图**
	UIView *subView = [[UIView alloc]init];
    subView.backgroundColor = [UIColor greenColor];
    [bgView addSubview:subView];
    [subView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(bgView).with.offset(10);
        make.left.equalTo(bgView).with.offset(20);
        make.bottom.equalTo(bgView).with.offset(-10);
        make.right.equalTo(bgView).with.offset(-50);
        make.height.lessThanOrEqualTo(bgView);
    }];

OC的方法 都是以 [] 这种形式掉用的 ,可是从上边可以看到 make.top.equalTo() 是链式掉用 那么他是怎么实现的呢?其实就是block 接下来通过看源码 来读读他是怎么实现的

约束配置类 MASConstraintMakerMASConstraintMaker 所拥有属性的一部分

我们以top 为例 来看他的get 方法

- (MASConstraint *)top {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}

通过他的层层掉用 发现他最终在 下面这个方法

- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

**我们来分析constraint 方法 **
从 self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute 代码来看 掉用.top的时候 其实直接走到了 if (!constraint) {} 这个代码分支 此时此刻 self.constraints 里有值了 并且是 MASViewConstraint 的对象 并且此方法返回了一个MASViewConstraint对象 下面分析 MASViewConstraint

约束的生成和添加类 MASViewConstraint

MASViewConstraint 继承于MASConstraint 这个很关键
我们来看他的初始化方法- (id)initWithFirstViewAttribute:
入参是一个MASViewAttribute 对象其实就是保存了一个约束的一个属性 这里就是 top 其实就是 NSLayoutAttributeTop
再来看一看 make.top.equalTo
equalTo 是 MASConstraint的一个block 这就是链式掉用的实现方式 我们来看这个equalTo方法的实现

- (MASConstraint * (^)(id))equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
} 

注意 注意 注意 ! 最终 掉用到了 equalToWithRelation block 关键方法来了

- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation {
    return ^id(id attribute, NSLayoutRelation relation) {
        if ([attribute isKindOfClass:NSArray.class]) {
            NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
            NSMutableArray *children = NSMutableArray.new;
            for (id attr in attribute) {
                MASViewConstraint *viewConstraint = [self copy];
                viewConstraint.layoutRelation = relation;
                viewConstraint.secondViewAttribute = attr;
                [children addObject:viewConstraint];
            }
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self.delegate;
            [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        } else {
            NSAssert(!self.hasLayoutRelation || self.layoutRelation == relation && [attribute isKindOfClass:NSValue.class], @"Redefinition of constraint relation");
            self.layoutRelation = relation;
            self.secondViewAttribute = attribute;
            return self;
        }
    };
}

我们在前边传入 equalToWithRelation 方法的 参数是 bgView 和 NSLayoutRelationEqual 我们这里传入的是 单个 所以直接走 else分支 relation 和 attribute 都赋值给了 self.layoutRelation self.secondViewAttribute 此时的self 是谁呀 是 MASViewConstraint 对象吧 是 前面声明的 newConstraint 吧 此时此刻我们的约束都装进了 newConstraint 中 统一保管
接下来一个关键 方法 MASConstraintMaker 的 install 方法

所有约束进行装配 install

哈哈 其实 上边说的 MASConstraintMaker 的 install 方法 只是个幌子 来看看他的实现

- (NSArray *)install {
    if (self.removeExisting) {
        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;
}

因为我们现在是添加操作 其实 if (self.removeExisting) { } 这个分支是不会走的 直接往下看 真正的装配方法 是走的 [constraint install];
其实 最终走的是 MASViewConstraint 的 install 方法 下面来看 install 方法的其中两行
回到原生AutoLayout 生成一个约束
MASLayoutConstraint *layoutConstraint
= [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
**将约束加到view上 在这个例子中是 subView **
[self.installedView addConstraint:layoutConstraint];
至此我们的一个top 约束添加完毕
可以参考https://github.com/SnapKit/Masonry 看看原生是怎么掉用的 结合Masonry源码看

后记

感谢有这些大牛的存在 正是有了他们的存在才使我们的开发更简单
怀着一颗感恩的心读他们的代码
这是我第一篇在csdn 上写博客 关于对Masonry 的分析 这只是一部分 读者可以发现 这只是一种情况 文中提到的方法 有一些if 分支是没有分析的 以后再补上。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值