约束代码混用的问题
无数人趟过此坑,大部分人在坑中一蹶不振,小部分人爬起来也是跌跌撞撞。
有很多人都说auto layout和manual layout的坐标设置是不能混用的,会导致出现布局问题。首先声明一点,autolayout和manuallayout是可以混用的。用的时机很重要,auto layout和manual layout有各自的生命周期和作用域,区分他们两个的作用时间很关键,头脑中一定要清楚你所添加的每条约束,在什么时间场合,会造成什么后果。否则,布局就会和预想的不同,各种奇怪的布局问题也就接踵而至。
1)视图的生命周期顺序
我们在controller视图上面用auto layout添加了一个subview,并在各个系统调用声明周期方法中做了打印处理,结果如下:
其中前面带有“-”符号的表示的是subview视图的打印。
autolayout的作用范围是从上往下第三个方法-updateConstraints一直到viewDidLayoutSubviews,这期间,系统是通过view上的约束来计算view上的布局。而我们一般习惯将布局写在viewDidLoad里面,这就是我们为什么总是无法用manual layout的方法去修改我们的布局。
要想修改布局,必须要在autolayout结束之后才会起作用,否则会被系统将我们的布局按照autolayout重新刷新,从上面我们可以看到,我们可以在子视图的-layoutSubviews和-drawRect方法里面修改子视图的布局,但是一般视图为了重用不会在自己的类里面将frame写死,这样我们只有通过controller的viewDidAppear方法修改视图的frame。但是这样也有问题,在viewDidAppear里面修改布局,我们可以看到一个明显的延迟,系统调用次序使然,我们无法去改变。除此之外,如果我们更新了视图的autolayout,会导致视图重新调用updateViewConstraints方法,viewDidAppear在进入页面的时候却只调用一次,结果就是subview又恢复了原来的样子。
所以我的建议就是不要同时manual layout+auto layout去控制同一个视图。始终记得如果用了auto layout去控制了一个视图,那么就要坚持用下去。
2)何为混用
我觉得混用的说法不是对于某一个视图说的,是说我们整个布局当中交叉使用了manual layout + auto layout,比如我们可以用auto layout布局viewA,然后用manual layout 布局B,然后将A与B用两者其一的方式,添加到共同的父viewC上,这就是我所认为的混用。
那么它的意义是什么呢?不同view的复杂度决定了我们采取哪种方式来对其布局,我们在开发中有可能会遇到某些流式的布局,我们用autolayout可以行云流水,但是对于某个视图当中极其复杂的小控件的布局,auto layout显然要写不少的一大段,当两者组合时也就是混用的意义所在。
3)如何混用
混用的风险其实一点不比它带来的好处小,首先解释一个名字
NSAutoresizingMaskLayoutConstraint
这个类型和NSLayoutConstraint 功能类似,它是个私有类,我们无法获取到,因为苹果ios6之后推出了auto layout技术,但是还想兼容原来的autoresizing,所以它将autoresizing转化为了约束,转化后的约束类型就是NSAutoresizingMaskLayoutConstraint,这就有可能导致系统为我们添加了许多我们无法预料的约束。
我们有时候会发现我们的约束没有写全,但是布局却很好,千万不要太得意,这只是系统帮你完成你该做的,这种情况固然对我们有好处。但是在manual layout + auto layout布局中就会发生大问题,系统不懂我们是在故意不写它的约束(因为我们打算手动布局这一块的视图),它就默默帮我们加上了谁都不知道的约束,并为自己的机智暗自欣喜。我们要明确告诉它我不需要你的帮助才行。
UIView里translatesAutoresizingMaskIntoConstraints属性就是用来控制是否允许系统做这样的转化,默认是YES。所以我们要把它设置为NO,然后将你漏掉的约束统统加上。
怎样算作完备的约束呢,我的建议是把视图层次分清楚,每个层次系统内部使用统一的布局方案,并保证系统内的的约束完整。
这是一个视图的层级拓扑结构(原谅我又盗图了,凑合看吧),如果我打算在做黄箭头位置的视图布局时采用auto layout,其他采用manual layout那么我只需保证它及它下面的两个子视图之间的约束完整就可以了,他们三个可以当做一个小的系统,系统内的约束只与他们自己相关,像下面两个红线连接的视图间的约束就是不允许添加的。
图:错误的约束关系
4)最后
以上就是我想说的,混用这种手段还是希望大家谨慎使用为好,最后总结一下混用的关键点
1.首先要确保在你打算使用手写auto layout为view布局前,将其translatesAutoresizingMaskIntoConstraints属性设为NO
2.不要用对同一个视图同时使用manual layout + auto layout
3.确保你的约束在其系统内完整无缺失。