masonry更新xib约束探索

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

内容简介:首先做个简单的小实验,在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的约束让人费解。还有待探索。


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

查看所有标签

猜你喜欢:

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

社会工程

社会工程

海德纳吉 (Christopher Hadnagy) / 陆道宏、杜娟、邱璟 / 人民邮电出版社 / 2013-12 / 59.00元

本书首次从技术层面剖析和解密社会工程手法,从攻击者的视角详细介绍了社会工程的所有方面,包括诱导、伪装、心理影响和人际操纵等,并通过凯文 · 米特尼克等社会工程大师的真实故事和案例加以阐释,探讨了社会工程的奥秘。主要内容包括黑客、间谍和骗子所使用的欺骗手法,以及防止社会工程威胁的关键步骤。 本书适用于社会工程师、对社会工程及信息安全感兴趣的人。一起来看看 《社会工程》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具