美文网首页
Autoresizing小坑一枚

Autoresizing小坑一枚

作者: 卖萌凉 | 来源:发表于2015-11-05 19:53 被阅读125次

因为使用简单,autoresizing的自动布局方式一直挺受我偏爱的。然而前端时间测试的时候,出现了几个布局上的bug,调试后发现原来是没有用正确姿势使用autoresizing所致的(╥﹏╥)。

为了描述一下这个bug,假装我写了这样一段代码:

CGRect parentFrame = CGRectMake(0, 0, 100, 100);
UIView *parent = [[UIView alloc] initWithFrame:parentFrame];
parent.backgroundColor = [UIColor redColor];
[self.view addSubview:parent];

UIView *son = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 100, 50)];
son.backgroundColor = [UIColor blueColor];
son.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[parent addSubview:son];

[parent setFrame:CGRectMake(0, 0, 100, 0)];
[parent setFrame:parentFrame];

大意是,希望son这个视图的底部永远和parent视图的底部对齐,而son视图的顶部永远和parent视图的顶部有50单位的距离。也就是这样的结果:

我期待的结果(●°u°●)​ 」

但是运行完这段代码后我得到的结果是这样的:


我得到的结果∑(゚Д゚)

于是bug就产生了(╥﹏╥)

为什么会这样呢?明明正确设置了autoresizing参数,可最后得到了错误的布局结果。仔细一想,原来是因为其中经历了

[parent setFrame:CGRectZero];

这个步骤。

在我的理解中,如果仅有UIViewAutoresizingFlexibleHeight,则表示,无论parent视图的尺寸如何变化,son视图的上边界和parent视图的上边界的距离不变,son视图的下边界和parent视图的下边界的距离不变,写成公式可能就是:

CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) 不变
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) 不变

最开始,parent视图的bounds(0, 0, 100, 100),而son视图的frame(0, 50, 100, 50),也就是说:

CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = 0

后来,parent视图的bounds变为(0, 0, 0, 0),此时若输出son视图的frame,会发现frame = (0 50; 0 0)。也就是说这个时候

CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = -50

这个结果和我所理解的UIViewAutoresizingFlexibleHeight矛盾了。

矛盾就出在,如果要严格按照“不变”的规则行事的话,此时son.frame.size.height应该为-50才对。
但是尺寸怎么可以是负值呢,可能autoresizing出于这个考虑,将-50的高度处理成了0。这也就说明,在程序执行到这一步的时候,失去了-50这个信息。

最后,当parent视图的bounds回到(0, 0, 100, 100)的时候,autoresizing保持了

CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = -50

这个关系不变,导致了son视图的高度最终变成了100。看一眼代码最终执行的结果,果然是这样。

所以,我的bug就出在,同事因为他的业务需要,改变了我负责的最外层视图的frame,而后又将其改回原值(他以为什么也不会发生,我开始也这么以为……),这个过程中,我负责的子视图在autoresize时出现了刚才的问题,导致最后呈现出了错误的布局。


在解决这个问题的时候,我还想到了,如果autoresizing不将负值的宽高转换成0,会怎样呢?
试了试,发现UIView会自动将负值的宽高转换成正值。

比如执行完这几行代码后

UIView *view = [[UIView alloc] init];
CGRect rect = CGRectMake(100, 100, -50, -50);
view.frame = rect;

打印view视图,会发现

<UIView: 0x7ff88bd4db00; frame = (50 50; 50 50); layer = <CALayer: 0x7ff88bd4d330>>

view视图的frame被转换了。

所以不管怎么样,使用autoresizing时,如果不小心让某个视图的宽高变成了负值,则一定会损失一部分信息,导致最后即便父视图的frame回到原值,子视图的frame也会出现问题。

相关文章

网友评论

      本文标题:Autoresizing小坑一枚

      本文链接:https://www.haomeiwen.com/subject/avbqhttx.html