masonry更新xib约束探索

栏目: IOS · 发布时间: 5年前

内容简介:首先做个简单的小实验,在storyboard拖放一个view,添加好约束。之后利用masonry分别去更新这个视图的位置,尺寸。会发现不一样的结果。如果你这么做会惊奇的发现更新位置有效,更新尺寸无效。why?到底用masonry能不能更新xib上的约束?带着这个问题我们去深入探索。其实上面两个小实验控制台都有打印警告

首先做个简单的小实验,在storyboard拖放一个view,添加好约束。之后利用masonry分别去更新这个视图的位置,尺寸。会发现不一样的结果。

//更新尺寸
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    
    [self.viewTest mas_updateConstraints:^(MASConstraintMaker *make) {
       //和storyboard中的约束相同
        make.width.mas_equalTo(375.0);
    }];
}
//更新位置
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    
    [self.viewTest mas_updateConstraints:^(MASConstraintMaker *make) {
       //和storyboard中的约束相同
        make.left.equalTo(self.viewTest.superview);
    }];
}
复制代码

如果你这么做会惊奇的发现更新位置有效,更新尺寸无效。why?到底用masonry能不能更新xib上的约束?带着这个问题我们去深入探索。

探索

第一步:查看源代码

其实上面两个小实验控制台都有打印警告

masonry更新xib约束探索

大致意思是说约束冲突。分析控制台中的两个约束,第二个应该是xib上的约束(有个55常量),第一个是我们更新后多出来的(MASLayout)。

那说明mas_updateConstraints导致多出来一个约束导致了约束冲突。让我们看看源代码。

//调用代码
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    //更新存在的约束
    constraintMaker.updateExisting = YES;
    block(constraintMaker);
    return [constraintMaker install];
}

//最终要执行的代码
- (void)install {
    if (self.hasBeenInstalled) {
        return;
    }
    .......
     MASLayoutConstraint *existingConstraint = nil;
    //判断是否更新存在约束(刚刚这里赋值了YES)
    if (self.updateExisting) {
        //下边去当前view上的约束里去匹配传过来的约束,如果相同返回这个约束,否则nil
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    //找到了匹配的约束
    if (existingConstraint) {
        // just update the constant
        //更新约束的值
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        //没找到匹配约束就在当前view上添加外边传过来的约束
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}

//遍历匹配当前view上的约束
- (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.
    /** 大致意思是倒序遍历查找约束,过滤掉了auto-resizing,interface builder 上的约束,也就是说遍历时候不考虑xib上的约束这样碰到xib上的约束后就直接continue了,最终会找不到匹配的约束返回nil */
    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;
}
复制代码

通过上面分析我们知道了,xib上的约束是不去匹配的最终existingConstraint被赋值了nil。导致最终执行了[self.installedView addConstraint:layoutConstraint];新加了一个约束。而这个新的约束往往是最高优先级的,并且xib上的约束发现默认也是最高优先级所以导致了约束冲突。控制台打印了警报。

第二步:验证

步骤一分析得出的结论是mas_updateConstraints方法导致新增了一个同优先级的约束导致了约束冲突。那我们尝试去改一下xib上的相应约束的优先级,调低些。在运行代码发现控制台并没有报错输出,同时无论更新尺寸还是位置都有效。这也进一步验证了步骤一的结论。

总结

通过以上分析得出,masonry不能直接更新xib上的约束。如果我们用mas_updateConstraints方法,masonry会新增一个约束,有可能会导致约束冲突,控制台打印警报,视图布局错乱。

那怎么去更新xib上的约束的。有两个方案,一是脱出来约束直接修改值。二是改变xib上的对应约束优先级,把优先级调低。然后用masonry去添加更高优先级的约束即可。相比较而言觉得方式一更好些。因为更改优先级其实就是要废掉xib上的约束,不够直接麻烦。

疑问

一开始的两个小实验,因为masonry不能直接更新xib上的约束,导致mas_updateConstraints方法实际上是新增了一个最高优先级的约束,导致约束冲突,控制台打印警报。这可以解释通。

但是为什么同样都是约束冲突,尺寸的约束冲突视图界面会用xib的约束。位置的约束冲突视图界面则用masonry的约束让人费解。还有待探索。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Writing Windows VxDs and Device Drivers, Second Edition

Writing Windows VxDs and Device Drivers, Second Edition

Karen Hazzah / CMP / 1996-01-12 / USD 54.95

Software developer and author Karen Hazzah expands her original treatise on device drivers in the second edition of "Writing Windows VxDs and Device Drivers." The book and companion disk include the a......一起来看看 《Writing Windows VxDs and Device Drivers, Second Edition》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具